https://cn.vjudge.net/contest/165707#problem/D
开始一直以为是有一个规律的。
按照结束的顺序从小往大排列,如果相同取花费时间最小的。
一直wa。wa到绝望。真没想到是状态压缩。。。
枚举每种状态,注意逆序输出的方法。
这题真是不错。
DP枚举每种状态的同时,最小化他要补的时间。
还要记录他的前面那个,用来输出用。
还要记录当前天数。。下一个递推要用。
还有一个重要的地方就是存的是之前的状态
而不是值。用值无法创建一个连续的地方
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
const int maxn=200;
struct Node
{ string s;
int first;//截止时间
int second;//要开始的时间
}node[maxn];
struct DP
{ int cost;//最小花费
int pre;//上一个数的状态
int date;//当前天数
}dp[1<<20];
void output(int n)
{ if(n==0)return;
int sta=n^dp[n].pre;
sta>>=1;
int pos=0;
while(sta)
{ sta>>=1;
pos++;
}
output(dp[n].pre);
cout<<node[pos].s<<endl;
}
int main()
{ int m;
int t;
scanf("%d",&t);
while(t--)
{ cin>>m;
memset(dp,0,sizeof(dp));
for(int i=0;i<m;i++)
{ cin>>node[i].s;
cin>>node[i].first;
cin>>node[i].second;
}
int all=(1<<m)-1;
bool vis[(1<<m)];
memset(vis,false,sizeof(vis));
vis[0]=true;
for(int i=0;i<all;i++)
{ for(int j=0;j<m;j++)
{ if(!(i&(1<<j)))
{ int dat=dp[i].date+node[j].second;//干完这个工作,干到哪了
int cos=dat-node[j].first;//要增加的时间
if(cos<0) cos=0;
int status=i|(1<<j);
dp[status].date=dat;
cos+=dp[i].cost;
if(!vis[status])
{ vis[status]=true;
dp[status].cost=cos;
dp[status].pre=i;
}
if(vis[status]&&dp[status].cost>cos)
{ dp[status].cost=cos;
dp[status].pre=i;
}
}
}
}
cout<<dp[all].cost<<endl;
output(all);
}
return 0;
}