/*状压dpD - Doing Homework时间: 2017/02/20题意:作业超过时限,超过一天扣一分,给出n个作业及其时限和需要完成的时间,求最小扣分值和其路径题解:状态压缩dp,本应该要想到的。其N<=15,根据选没选压成二进制因为题目要求最后方案如果多个情况以字典序排序,所以可以先将原数据先排序然后我们发现递归时缺少了上一个状态的所用时间,我先预处理出来。设这个状态为wi,上个状态为wj,这个状态和上个状态相差的那个作业的编号为id那么 dp[wi] = dp[wj]+time[wj]+C[id]-D[id]。*/#include<cstdio>#include<cstring>#include<cmath>#include<iostream>#include<algorithm>#include<queue>#include<map>using namespace std;#define N 110#define INF 0x3f3f3f3fstruct asd{ char name[N]; int a,b;}node[20];bool cmp(asd x,asd y){ return strcmp(x.name,y.name)>0;}int dp[1<<15],time[1<<15],PRe[1<<15];int main(){ int T; scanf("%d",&T); while(T--) { memset(dp,0,sizeof(dp)); memset(pre,0,sizeof(pre)); memset(time,0,sizeof(time)); int n; scanf("%d",&n); for(int i = 0; i < n; i++) cin >> node[i].name >> node[i].a >> node[i].b; sort(node,node+n,cmp); for(int i = 1; i < 1<<n; i++) { for(int j = i; j > 0; j -= (j&-j)) { int k = j&-j,num = 1; while(k>>num) num++; time[i] += node[num-1].b; } } for(int i = 1; i < 1<<n; i++) { dp[i] = INF; for(int j = i; j > 0; j -= (j&-j)) { int k = j&-j,num = 1; while(k>>num) num++; int ans = time[i & ~(j&-j)]+node[num-1].b-node[num-1].a; ans = ans<0?0:ans;// dp[i] = min(dp[i],dp[i & ~(j&-j)] + ans); if(dp[i] > dp[i & ~(j&-j)]+ans) { dp[i] = dp[i & ~(j&-j)]+ans; pre[i] = num-1; } } } printf("%d/n",dp[(1<<n)-1]); int val = (1<<n)-1; int res[20]; int id = 0; while(1) { res[id++] = pre[val]; //printf("%s/n",node[pre[val]].name); val -= 1 << pre[val]; if(val == 0) break; } for(int i = id-1; i >= 0; i--) printf("%s/n",node[res[i]].name); } return 0;}
新闻热点
疑难解答