0x1f 题目:
0x2f 题意:
- 定义初始背包的最优解Vmax
- 定义n个物品去掉任意一个后,最优解为Vmax′
- 每一个物品w[i],v[i],在v[i]上加上一个最小值,使得Vmax > Vmax′
- 背包的容量是m
0x3f 思路:
- 前缀背包:pre[i][j] 表示前 i 个物品使用体积为 j 的最大价值
- 后缀背包:suf[i][j] 表示 i 之后物品使用体积为 j 的最大价值(转移的方法和01背包一样)
- 接下来贪心考率在什么情况下Vmax > Vmax′
- 计算Vmax′:max0→mj(pre[i−1][j]+suf[i+1][m−j])
- 要让Vmax > Vmax′成立,可以在背包里提前预留w[i],计算出最大值,要让物品i成为必需品,至少需要加上 Vmax + 1 - (Vmax′+v[i])
- 为什么?因为贪心结果是必须把物品 i 放入背包的,只有这一个物品,容易贪心留w[i]的空间是最优的
- 计算预留w[i]空间:max0→m−w[i]j(pre[i−1][j]+suf[i+1][m−j−w[i]])
0x4f 代码:
//
using namespace std
typedef long long LL
typedef unsigned long long ULL
typedef pair<int,int> PII
typedef pair<LL,LL> PLL
//
//
inline int rd()
{
int f=1,x=0
while(c<'0'||'9'<c){if(c=='-')f=-1
while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar()
return f*x
}
//常数定义
const double eps = 1e-6
const double PI = acos(-1.0)
const int INF = 0x3f3f3f3f
const int N = 5010
void solve(){
int n, m
vector<int>w(n), v(n)
for(int i = 0
cin >> w[i] >> v[i]
}
vector<vector<LL>> pre(n, vector<LL>(m + 1))
vector<vector<LL>> suf(n, vector<LL>(m + 1))
for(int i = 0
if(i) pre[i] = pre[i - 1]
for(int j = m
pre[i][j] = max(pre[i][j], pre[i][j - w[i]] + v[i])
}
}
for(int i = n - 1
if(i < n - 1) suf[i] = suf[i + 1]
for(int j = m
suf[i][j] = max(suf[i][j], suf[i][j - w[i]] + v[i])
}
}
for(int i = 0
LL max1 = 0, max2 = 0
for(int j = 0
max1 = max(max1, (i ? pre[i - 1][j] : 0) + (i + 1 < n ? suf[i + 1][m - j] : 0))
}
for(int j = 0
max2 = max(max2, (i ? pre[i - 1][j] : 0) + (i + 1 < n ? suf[i + 1][m - j - w[i]] : 0))
}
cout << max(0LL, max1 + 1 - v[i] - max2) << "\n"
}
}
signed main()
{
/*
ios::sync_with_stdio(false)
cin.tie(0)
cout.tie(0)
*/
//caseT
solve()
return 0
}
/*
*/