HDU 1074 Doing Homework(状压DP输出路径)

大概题意是有n门作业,对于每一门作业,他做完需要C天,但是作业要在D天之前交,玩一天扣一分,问如何排列作业的顺序使得扣得分最少...

状压DP,暑假的时候做过这个题目,当时没做出来找学长帮忙了...现在做起来依旧很吃力,还找出来以前的程序对照了一下...。

思路就是,当一个状态值是x的时候,他有a个1,那么x的最优情况是从有a-1个1并且加上一个1能得到x的所有状压值里面的最优解...比如完成之后是110的,他可能由010和100得到...然后只需要记录一下路径就好了....

#include<cstdio>
#include<cstring>
#define INF 0x3fffffff
struct node
{
    char name[110];
    int die;
    int need;
}st[30];
struct stsort
{
    int need;
    int t;
    int qian;
}dp[1<<16];
int limit;
void print(int x)
{
    int ans[30];
    int l=0;
    while(x>0)
    {
        ans[l++]=dp[x].qian;
        x=x-(1<<dp[x].qian);
    }
    l--;
    while(l>=0)
    {
        printf("%s\n",st[ans[l]].name);
        l--;
    }
    return ;
}
int getadd(int pos,int j)
{
    int i,top,low,sum=0;
    low=dp[pos-(1<<j)].need;
    top=low+st[j].need;
    pos=pos-(1<<j);
    for(i=0;(1<<i)<limit;i++)
    {
        if(((1<<i)&pos)==0)
        {
            if(st[i].die<top)
                sum+=st[i].die<low?(top-low):(top-st[i].die);
        }
    }
    return dp[pos].t+sum;
}
int main()
{
    int i,j,n,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        limit=1<<n;
        for(i=0;i<limit;i++)
            dp[i].t=INF;
        dp[0].t=dp[0].need=0;
        for(i=0;i<n;i++)
            scanf("%s %d%d",st[i].name,&st[i].die,&st[i].need);
        for(i=0;i<limit;i++)
        {
            for(j=0;(1<<j)<=i;j++)
            {
                if(((1<<j)&i)!=0)
                {
                    if(dp[i].t>getadd(i,j))
                    {
                        dp[i].t=getadd(i,j);
                        dp[i].need=dp[i-(1<<j)].need+st[j].need;
                        dp[i].qian=j;
                    }
                    else if(dp[i].t==getadd(i,j)&&strcmp(st[j].name,st[dp[i].qian].name)>0)
                        dp[i].qian=j;
                }
            }
        }
        printf("%d\n",dp[limit-1].t);
        print(limit-1);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值