lightoj1037_状压dp
Posted _lm
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了lightoj1037_状压dp相关的知识,希望对你有一定的参考价值。
题目链接:http://lightoj.com/volume_showproblem.php?problem=1037
题意:你现在需要消灭n个敌人,n个敌人的血量已知,你的普通攻击力为1,但是如果你杀死敌人i可以用它的武器去杀死其他敌人,b[i][j] 表示用敌人i的武器射杀敌人j会减b[i][j]滴血.问你最少可以攻击多少次可以将敌人杀死。
思路:
定义集合s为死亡敌人的集合。
dp[s] 为让集合为s的人死亡最小需要的攻击次数。
如果现在想要消灭敌人i 并且敌人i不属于s
那么dp[s | (1<<i)] = min(dp[s|(1<<i)] , dp[s] + t);
t 为用死亡敌人的武器消灭敌人i的最小费用。如何求t成为了本题的关键。
考虑死亡敌人集合s,你同样也拥有了死亡敌人j的武器【j属于集合s】
那么t = min(t, 用敌人j 的武器射杀i的次数) 【j属于集合s】
当t一次都没有被更新时,说明死亡敌人的武器没有可以消灭敌人i的,只能用普通武器攻击
1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cstdio> 6 #include <vector> 7 #include <ctime> 8 #include <queue> 9 #include <list> 10 #include <set> 11 #include <map> 12 using namespace std; 13 #define INF 0x3f3f3f3f 14 typedef long long LL; 15 16 int a[20], b[20][20], x[20], y[20]; 17 int dp[20][1<<15]; 18 char bb[20][20]; 19 int main() 20 { 21 int t, n; 22 scanf("%d", &t); 23 for(int ca = 1; ca <= t; ca++) 24 { 25 scanf("%d", &n); 26 for(int i = 1; i <= n ; i++) 27 scanf("%d", &a[i]); 28 for(int i = 1; i <= n; i++) 29 scanf("%s", bb[i]); 30 for(int i = 1; i <= n; i++) 31 for(int j = 0; j < n; j++) 32 b[i][j+1] = bb[i][j] - ‘0‘; 33 memset(dp, INF, sizeof(dp)); 34 for(int i = 0; i < n; i++) 35 dp[1][1<<i] = a[i+1]; 36 for(int i = 2; i <= n; i++) 37 { 38 for(int j = 1; j < (1 << n); j++) 39 { 40 int te = j; 41 int l1 = 0, l2 = 0, l3 = 0; 42 while(te) 43 { 44 if(te % 2) 45 x[++l1] = l3;//1 46 else 47 y[++l2] = l3;//0 48 te >>= 1; 49 l3++; 50 } 51 while(l3 < n) 52 { 53 y[++l2] = l3; 54 l3++; 55 } 56 if(l1 != i-1) 57 continue; 58 for(int k1 = 1; k1 <= l2; k1++)//0, l2, y 59 { 60 int tx = 0; 61 for(int k2 = 1; k2 <= l1; k2++)//1, l1, x 62 { 63 if(b[x[k2]+1][y[k1]+1] > tx) 64 { 65 tx = b[x[k2]+1][y[k1]+1]; 66 } 67 } 68 if(tx == 0) 69 dp[i][j|(1<<y[k1])] = min(dp[i][j|(1<<y[k1])], dp[i-1][j] + a[y[k1]+1]); 70 else if(a[y[k1]+1] % tx) 71 dp[i][j|(1<<y[k1])] = min(dp[i][j|(1<<y[k1])], dp[i-1][j] + a[y[k1]+1] / tx + 1); 72 else if(a[y[k1]+1] % tx == 0) 73 dp[i][j|(1<<y[k1])]= min(dp[i][j|(1<<y[k1])], dp[i-1][j] + a[y[k1]+1] / tx); 74 } 75 } 76 } 77 int res = dp[n][(1<<n)-1]; 78 printf("Case %d: %d\n", ca, res); 79 } 80 return 0; 81 }
以上是关于lightoj1037_状压dp的主要内容,如果未能解决你的问题,请参考以下文章
LightOJ1158 Anagram Division(状压DP)
LightOJ1316 A Wedding Party(状压DP)
lightoj 1119 - Pimp My Ride(状压dp)