dp - 3维背包(东四省)
题意:
给你 n 张卡片,总共可以消耗的法力值,求最多可以造成多少伤害, 卡片分为2种,一种是魔法卡,使用后可以使所有的连环卡的费用全部减1,另一种是连环卡,因魔法卡的使用可以使其费用减1,问最终最多可以造成多少的伤害
思路分析 :
比赛的时候大脑短路了,基本不愿意去想东西了,导致题目没有出来,这个题就是一个 01背包,但是增加了一个限制条件,所以我们多增加一维表示到当前位置,所使用的魔法卡的数量,但是呢,还有一个很关键的地方,就是我们要先对卡片经行一个排序的预处理,这样在搞 dp的时候,才不会对后续有任何的影响,排序的时候,优先使用魔法卡,然后两者都是的卡,剩下的卡就随意了。
代码示例:(未测试)
#define ll long long const int maxn = 1e6+5; const int mod = 1e9+7; const double eps = 1e-9; const double pi = acos(-1.0); const int inf = 0x3f3f3f3f; int n, w; struct node { int w, x, p1, p2; }pre[505]; int dp[505][505][505]; int cnt = 0; bool cmp1(node a, node b){ if (a.p1 == b.p1) return a.p2 < b.p2; return a.p1 > b.p1; } bool cmp2(node a, node b){ if (a.w == b.w) return a.x > b.x; return a.w < b.w; } void fun(){ for(int i = 1; i <= n; i++){ for(int j = 1; j <= w; j++){ for(int k = 0; k <= min(i, cnt); k++){ // 使用魔法卡 if (pre[i].p1 && !pre[i].p2) { // 1 0 if (j >= pre[i].w && k) dp[i][j][k] = max(dp[i-1][j][k], dp[i-1][j-pre[i].w][k-1]+pre[i].x); else dp[i][j][k] = dp[i-1][j][k]; } else if (pre[i].p1 && pre[i].p2){ // 1 1 int cost = max(pre[i].w-k+1, 0); //if (i == 2 && j == 2) printf("cost = %d\n", cost); if (j >= cost && k){ dp[i][j][k] = max(dp[i-1][j][k], dp[i-1][j-cost][k-1]+pre[i].x); } else dp[i][j][k] = dp[i-1][j][k]; } else if (!pre[i].p1 && pre[i].p2){ // 0 1 int cost = max(pre[i].w-k, 0); if (j >= cost && k){ dp[i][j][k] = max(dp[i-1][j][k], dp[i-1][j-cost][k]+pre[i].x); } else dp[i][j][k] = dp[i-1][j][k]; } else { // 0 0 if (j >= pre[i].w){ dp[i][j][k] = max(dp[i-1][j][k], dp[i-1][j-pre[i].w][k]+pre[i].x); } else dp[i][j][k] = dp[i-1][j][k]; } //printf("+++%d %d %d = %d \n",i, j, k, dp[i][j][k]); } } } } void init(){ int pos1 = -1, pos2 = -1; for(int i = 1; i <= n; i++){ if (pre[i].p1 && !pre[i].p2) { pos1 = i; break; } } for(int i = n; i >= 1; i--){ if (pre[i].p1 && !pre[i].p2) { pos2 = i; break; } } if (pos1 != -1) sort(pre+pos1, pre+pos2+1, cmp2); pos1 = pos2 = -1; for(int i = 1; i <= n; i++){ if (pre[i].p1 && pre[i].p2) { pos1 = i; break; } } for(int i = n; i >= 1; i--){ if (pre[i].p1 && pre[i].p2) { pos2 = i; break; } } if (pos1 != -1) sort(pre+pos1, pre+pos2+1, cmp2); pos1 = pos2 = -1; for(int i = 1; i <= n; i++){ if (!pre[i].p1 && !pre[i].p2) { pos1 = i; break; } } for(int i = n; i >= 1; i--){ if (!pre[i].p1 && !pre[i].p2) { pos2 = i; break; } } if (pos1 != -1) sort(pre+pos1, pre+pos2+1, cmp2); pos1 = pos2 = -1; for(int i = 1; i <= n; i++){ if (!pre[i].p1 && pre[i].p2) { pos1 = i; break; } } for(int i = n; i >= 1; i--){ if (!pre[i].p1 && pre[i].p2) { pos2 = i; break; } } if (pos1 != -1) sort(pre+pos1, pre+pos2+1, cmp2); } int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); cin >> n >> w; for(int i = 1; i <= n; i++){ scanf("%d%d%d%d", &pre[i].w, &pre[i].x, &pre[i].p1, &pre[i].p2); if (pre[i].p1 == 1) cnt++; } sort(pre+1, pre+1+n, cmp1); init(); for(int i = 1; i <= n; i++){ printf("%d%d%d%d\n", pre[i].w, pre[i].x, pre[i].p1, pre[i].p2); } memset(dp, 0x8f, sizeof(dp)); for(int j = 0; j <= w; j++) { dp[0][j][0] = 0; } fun(); int ans = 0; for(int i = 0; i <= cnt; i++) ans = max(ans, dp[n][w][i]); printf("%d\n", ans); return 0; } /* 4 3 1 3 0 1 1 0 0 0 3 3 1 1 3 4 1 0 3 3 3 3 1 1 2 3 1 1 1 3 1 1 3 4 3 10 1 1 30 400 1 1 4 200 1 1 5 5 6 50 1 1 3 30 0 1 3 3 1 0 3 200 0 0 3 6 1 0 6 4 1 3 1 0 2 5 0 0 1 2 0 1 2 2 1 1 3 4 0 1 1 1 1 0 */
东北日出西边雨 道是无情却有情