HDOJ 1074 Doing Homework (DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1074

思路:暴力。但是N=15,15!的暴力必然超时。问题为求完成N个作业后的最短罚时,考虑如果知道N-1个的最短罚时,能否求出N个作业的最短罚时,发现可行,把N个作业是否完成用二进制表示,则复杂度降为(2^N)。

输出路径,网传的很多代码都是错的,数据不够强。要输出的字典序最小,倒着找必须遍历所有可能性,因为后面贪心找字典序大的可能导致第一个课程的字典序比答案要大,所以要写个DFS遍历一次。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n,ans[16],ct,temp[16],MAX;
struct node
{
    int sum;
    int res;
}dp[1<<15];
struct node1
{
    string s;
    int d,c;
}info[16];
bool cmp(node1 a,node1 b)
{
    return a.s>b.s;
}
void init()
{
    memset(dp,-1,sizeof(dp));
    dp[0].sum=dp[0].res=0;
    ct=0;
    MAX=-1;
}
void read()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>info[i].s>>info[i].d>>info[i].c;
    }
    sort(info,info+n,cmp);
}
void rundp()
{
    for(int i=1;i<(1<<n);i++)
    {
        for(int j=0;j<n;j++)
        {
            int j1=1<<j;
            if(i&j1)
            {
                int pre=i-j1;
                int cost=dp[pre].sum+info[j].c-info[j].d;
                if(cost<0)  cost=0;
                if(dp[pre].res+cost<dp[i].res||dp[i].res==-1)
                {
                    dp[i].res=dp[pre].res+cost;
                    dp[i].sum=dp[pre].sum+info[j].c;
                }
            }
        }
    }
}
void dfs(int now,int depth)
{
    if(now==0)
    {
        if(MAX<temp[depth-1])
        {
            MAX=temp[depth-1];
            for(int i=0;i<depth;i++)    ans[i]=temp[i];
        }
        return ;
    }
    for(int i=0;i<n;i++)
    {
        int j1=1<<i;
        if(j1&now)
        {
            int pre=now-j1;
            int cost=dp[pre].sum+info[i].c-info[i].d;
            if(cost<0)  cost=0;
            if(dp[pre].res+cost==dp[now].res)
            {
                temp[depth]=i;
                dfs(now-j1,depth+1);
            }
        }
    }
    return ;
}
void print()
{
    printf("%d\n",dp[(1<<n)-1].res);
    int state=(1<<n)-1;
    for(int i=n-1;i>=0;i--)
    {
        cout<<info[ans[i]].s<<endl;
    }
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        init();
        read();
        rundp();
        dfs((1<<n)-1,0);
        print();
    }
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值