hdu-1074-状态压缩dp

第一次做状态压缩dp。

这里注意一个点就是枚举n个作业的顺序不同从而使得更新条件不同。

当正向也就是1-n枚举时候,dp[i]>=dp[i-temp]+score更新。

当逆向也就是n-1枚举的时候,dp[i]>dp[i-temp]+score更新。

题目要求多解下输出最小字典序,而且输入是按照字典序从小到大输入的,当逆序遍历时候,因为输出的是x-(1<<pre[x])这个状态,要想其越小,pre[x]越大,即j越大,所以找到可更新的j就停止,这样保证j是大的

#include <cstring>
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>

#define INF 0x3f3f3f3f

using namespace std;

const int maxn=(1<<15)+5;

struct P
{
    char s[105];
    int d,t;
}p[20];

int T,n;
int dp[maxn],pre[maxn],time[maxn];

void output(int x)
{
    if(!x) return ;
    output(x-(1<<pre[x]));
    printf("%s\n",p[pre[x]].s);
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        memset(time,0,sizeof(time));
        memset(pre,0,sizeof(pre));
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%s%d%d",&p[i].s,&p[i].d,&p[i].t);
        int state=1<<n;
        for(int i=1;i<state;i++)//先枚举所有状态
        {
            dp[i]=INF;//初始化这个状态的值
            for(int j=0;j<n;j++)
            {
                int temp=1<<j;//做这个作业
                if(!(i&temp)) continue ;//表示如果不能从i-temp转移到i,也就是做了j也打不到状态i就跳过
                int score=time[i-temp]+p[j].t-p[j].d;//i-temp表示从i-temp到i这个状态,也就是做了j这个作业
                //score表示如果做了j扣的分,time表示到达这个状态花的时间
                if(score<0) score=0;//扣分是负的,表示当前作业都能在规定时间内完成
                if(dp[i]>=dp[i-temp]+score)//从i-temp状态到i状态扣的分少就更新
                {
                    dp[i]=dp[i-temp]+score;
                    time[i]=time[i-temp]+p[j].t;//更新新状态花的时间
                    pre[i]=j;//记录节点方便输出
                }
            }
        }
        printf("%d\n",dp[state-1]);
        output(state-1);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/alusang/article/details/80918804
今日推荐