hdu 1074(状态压缩dp+记录路径)

题意:给了n个家庭作业,然后给了每个家庭作业的完成期限和花费的实践,如果完成时间超过了期限,那么就要扣除分数,然后让你找出一个最优方案使扣除的分数最少,当存在多种方案时,输出字典序最小的那种,因为题意已经说了家庭作业的名字是按照字典序从小到大输入的,所以处理起来就好多了。

分析:此题的关键是如何记录路径,具体看代码实现吧!

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

struct node{
    char str[105];
    int dayline;
    int cost;
}a[20];

struct st{
    int now,pre;//now代表当前状态,pre代表当前状态的前一个状态
    int time;//当前时间
    int score;//当前扣除的分数
    int id;//当前刚做完的作业
}dp[35000];

int n;

void solve()
{
    int i,j,max=1<<n,qian,temp,num=0;
    char res[20][105];
    dp[0].now=0;
    dp[0].pre=0;
    dp[0].time=0;
    dp[0].score=0;
    dp[0].id=0;
    for(i=1;i<max;i++)
    {
        dp[i].score=100000000;
        for(j=0;j<=n-1;j++)
        {
            if(i&(1<<j))
            {
                qian=i-(1<<j);//由qian->i
                if(dp[qian].time+a[j+1].cost>a[j+1].dayline)
                 temp=dp[qian].time+a[j+1].cost-a[j+1].dayline;
                else
                 temp=0;
                //temp用来表示做了当前作业需要扣除的分数
                if(dp[i].score>=dp[qian].score+temp)//这里要取等号,自己想下为什么?如果去掉,会出现生命结果
                {
                    dp[i].score=dp[qian].score+temp;
                    dp[i].now=i;
                    dp[i].pre=qian;
                    dp[i].time=dp[qian].time+a[j+1].cost;
                    dp[i].id=j+1;
                }
            }
        }
    }
    printf("%d\n",dp[max-1].score);
    int t=max-1;
    while(dp[t].now!=0)//先把结果倒过来
    {
        strcpy(res[num++],a[dp[t].id].str);
        t=dp[t].pre;
    }
    for(i=num-1;i>=0;i--)
     printf("%s\n",res[i]);
}

int main()
{
    int T,i;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        getchar();
        for(i=1;i<=n;i++)
        {
            scanf("%s",a[i].str);
            scanf("%d",&a[i].dayline);
            scanf("%d",&a[i].cost);
            getchar();
        }
        solve();
    }
    return 0;
}

 

posted on 2013-11-29 19:09  后端bug开发工程师  阅读(891)  评论(1编辑  收藏  举报

导航