http://acm.hdu.edu.cn/showproblem.php?pid=1074
我们可以断定状态的终止态一定是n个数全部选完的情况,那么它的前一个状态是什么呢,一定是剔除任一门课程后的n种状态。
例如
dp[全选了]=min{(dp[除了math都做了]+math的超时天数),(dp[除了computer都做了]+computer的超时天数),(dp[除了english都做了]+english的超时天数)}那么接下来的dp状态依然如此。
好了,接下来,我们该如何去思考了,这个题目共有2^15种可能情况,对此我们通过位运算的方法降低它的维度。
二进制的每一位代表一门课,它的组合可以完成展示出所有的状态。
最后我们应该去思考一个问题,顺序的问题,我们知道,第一次取得时候,一定只有一个课程,如果我们以
1 int bit = 1<<n; 2 for(int i = 1;i<bit;i++)
能否确保某一个状态的前一个都完全包含,你可以自己去检验,是完全满足的.
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int MAXN = (1<<15)+10; 7 const int INF = 0x3f3f3f; 8 struct node 9 { 10 char str[105]; 11 int d;//the deadtime 12 int c;//need spend time 13 }; 14 node nd[20]; 15 int dp[MAXN],pre[MAXN],t[MAXN]; 16 void output(int x) 17 { 18 if(!x) 19 return ; 20 output(x-(1<<(pre[x]-1))); 21 printf("%s ",nd[pre[x]].str); 22 } 23 int main() 24 { 25 int cas,n; 26 scanf("%d",&cas); 27 while(cas--) 28 { 29 memset(t,0,sizeof(t)); 30 memset(pre,0,sizeof(pre)); 31 //memset(dp,0,sizeof(dp)); 32 scanf("%d",&n); 33 for(int i = 1;i<=n;i++) 34 { 35 scanf("%s%d%d",nd[i].str,&nd[i].d,&nd[i].c); 36 } 37 /* for(int i = 1;i<=n;i++) 38 { 39 printf("%s %d %d ",nd[i].str,nd[i].d,nd[i].c); 40 }*/ 41 int bit = 1<<n; 42 for(int i = 1;i<bit;i++) 43 { 44 dp[i] = INF; 45 for(int j = n;j>=1;j--) 46 { 47 int temp = 1<<(j-1); 48 if(!(temp&i)) 49 continue; 50 else 51 { 52 int dist = (t[i-temp]+nd[j].c-nd[j].d); 53 if(dist > 0) 54 { 55 if(dp[i]>(dp[i-temp]+dist)) 56 { 57 t[i]=t[i-temp]+nd[j].c; 58 dp[i]=dp[i-temp]+dist; 59 pre[i] = j; 60 } 61 } 62 else 63 { 64 if(dp[i]>dp[i-temp]) 65 { 66 t[i]=t[i-temp]+nd[j].c; 67 dp[i]=dp[i-temp]; 68 pre[i] =j; 69 } 70 } 71 } 72 } 73 } 74 cout<<dp[bit-1]<<endl; 75 output(bit-1); 76 } 77 return 0; 78 }