其实这个转移方程比较简单,每次枚举最后一个完成的作业就行了。
转移方程是 dp[i] = min{ dp[ i - (1<<(k-1)) ] + score(i,k) }
score(i,k)是完成i这么多作业中最后一个完成的作业是k时,k带来的最小扣分值。
难点在于字典序输出方案,我建了个ans数组ans[i]代表i状态下最好的完成的最后一个作业。要注意处理字典序的时候,要把从i到0的一整条方案都找到,【因为题目要求的就是如果有最佳方案,输出字典序最小的,而不是要第i个完成的课程字典序较小】,不能光比当前course的字典序。
1 #include<iostream> 2 #include<vector> 3 #include<algorithm> 4 #define INF 1000000000 5 using namespace std; 6 7 string course[20]; 8 int deadline[20],c[20],n; 9 int dp[66000];//dp[i]代表做完【i状态代表的这么多作业】最少扣分 10 //dp[0] = 0 11 int ans[66000]; 12 vector<string> path; 13 14 int finishday(int num){//N代价 15 int an=0; 16 for(int i=1;i<=n;i++){//枚举这种作业完成情况下有没有完成i 17 if( num & (1<<(i-1) ) ) an+=c[i]; 18 } 19 return an; 20 } 21 22 int score(int num,int k){//完成num状态这么多作业,最后一个完成的是k作业,k带来的扣分 23 int s = 0; 24 s = deadline[k] - finishday( num - (1<<(k-1)) ) - c[k];//要扣s分 25 if(s>0) s=0;//不用扣分 26 return -s; 27 } 28 29 int main(){ 30 int t; cin>>t; 31 while(t--){ 32 for(int i=0;i<66000;i++) dp[i]=INF; 33 cin>>n; 34 for(int i=1;i<=n;i++) cin>>course[i]>>deadline[i]>>c[i]; 35 36 dp[0]=0; 37 for(int i=1;i<= (1<<n)-1;i++){//枚举所有的作业完成状态 38 int best; 39 for(int k=1;k<=n;k++){//枚举最后一个作业做的是什么 40 if( i & (1<<(k-1) ) ) { 41 int cnt = dp[ i - (1<<(k-1) ) ] + score(i,k); 42 if( cnt<=dp[i] ){ 43 if( cnt < dp[i] ) best=k; 44 else{ 45 vector<int> path1,path2;//记录整条路径 46 int num = i - (1<<(k-1)); 47 path1.push_back(k); 48 while( ans[num]!=0 ){ int choose = ans[num]; path1.push_back(choose); num-=(1<<(choose-1)); } 49 num = i - (1<<(best-1)); 50 path2.push_back(best); 51 while( ans[num]!=0 ){ int choose = ans[num]; path2.push_back(choose); num-=(1<<(choose-1)); } 52 53 reverse( path1.begin(),path1.end() ); 54 reverse( path2.begin(),path2.end() ); 55 56 if( path1<path2 ) best=k; 57 }//选字典序大的 58 dp[i]=cnt; 59 } 60 } 61 } 62 ans[i]=best;//这种情况下最后一个完成的作业应该是best 63 //cout<<i<<" "<<best<<endl; 64 } 65 66 int num = (1<<n) -1; cout<<dp[num]<<endl; 67 while( ans[num]!=0 ){ 68 int k = ans[num]; 69 path.push_back( course[k] ); 70 num-=(1<<(k-1)); 71 } 72 for(int i=path.size()-1;i>=0;i--) cout<<path[i]<<endl; 73 path.clear(); 74 } 75 76 return 0; 77 }