HDU-1074-状态压缩DP

来源:互联网 发布:专业网络k歌声卡 编辑:程序博客网 时间:2024/05/21 11:32

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;}
原创粉丝点击