题意:给了n个家庭作业,然后给了每个家庭作业的完成期限和花费的实践,如果完成时间超过了期限,那么就要扣除分数,然后让你找出一个最优方案使扣除的分数最少,当存在多种方案时,输出字典序最小的那种,因为题意已经说了家庭作业的名字是按照字典序从小到大输入的,所以处理起来就好多了。
分析:此题的关键是如何记录路径,具体看代码实现吧!
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; struct node{ char str[105]; int dayline; int cost; }a[20]; struct st{ int now,pre;//now代表当前状态,pre代表当前状态的前一个状态 int time;//当前时间 int score;//当前扣除的分数 int id;//当前刚做完的作业 }dp[35000]; int n; void solve() { int i,j,max=1<<n,qian,temp,num=0; char res[20][105]; dp[0].now=0; dp[0].pre=0; dp[0].time=0; dp[0].score=0; dp[0].id=0; for(i=1;i<max;i++) { dp[i].score=100000000; for(j=0;j<=n-1;j++) { if(i&(1<<j)) { qian=i-(1<<j);//由qian->i if(dp[qian].time+a[j+1].cost>a[j+1].dayline) temp=dp[qian].time+a[j+1].cost-a[j+1].dayline; else temp=0; //temp用来表示做了当前作业需要扣除的分数 if(dp[i].score>=dp[qian].score+temp)//这里要取等号,自己想下为什么?如果去掉,会出现生命结果 { dp[i].score=dp[qian].score+temp; dp[i].now=i; dp[i].pre=qian; dp[i].time=dp[qian].time+a[j+1].cost; dp[i].id=j+1; } } } } printf("%d ",dp[max-1].score); int t=max-1; while(dp[t].now!=0)//先把结果倒过来 { strcpy(res[num++],a[dp[t].id].str); t=dp[t].pre; } for(i=num-1;i>=0;i--) printf("%s ",res[i]); } int main() { int T,i; scanf("%d",&T); while(T--) { scanf("%d",&n); getchar(); for(i=1;i<=n;i++) { scanf("%s",a[i].str); scanf("%d",&a[i].dayline); scanf("%d",&a[i].cost); getchar(); } solve(); } return 0; }