http://acm.hdu.edu.cn/showproblem.php?pid=1074php
咱們能夠判定狀態的終止態必定是n個數所有選完的狀況,那麼它的前一個狀態是什麼呢,必定是剔除任一門課程後的n種狀態。node
例如ios
dp[全選了]=min{(dp[除了math都作了]+math的超時天數),(dp[除了computer都作了]+computer的超時天數),(dp[除了english都作了]+english的超時天數)}那麼接下來的dp狀態依然如此。spa
好了,接下來,咱們該如何去思考了,這個題目共有2^15種可能狀況,對此咱們經過位運算的方法下降它的維度。code
二進制的每一位表明一門課,它的組合能夠完成展現出全部的狀態。blog
最後咱們應該去思考一個問題,順序的問題,咱們知道,第一次取得時候,必定只有一個課程,若是咱們以string
1 int bit = 1<<n; 2 for(int i = 1;i<bit;i++)
可否確保某一個狀態的前一個都徹底包含,你能夠本身去檢驗,是徹底知足的.it
代碼:io
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\n",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\n",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 }