您的位置:首页 > 其它

hdu 1074 DFS+状态压缩DP

2011-04-22 16:43 316 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1074

题意描述:小m现在需要完成 n (n<15)门课程的作业,每个作业都有截止时间还有完成该作业的天数,若完成作业的时间超过了截止时间,则会被扣分,超出1天扣1分,题目按字典序升序输入所有的作业名,现在需要你输出完成作业的顺序,以使得被扣除的分数最少。 如果存在多种方案,则按字典序最小的输出。

解题思路:完成同样的作业,如果安排的顺序不一样,被扣除的分数也就不一样,但是需要的时间是一样的。所以我们可以通过压缩状态(2进制映射成10进制)来进行最优解剪枝,题目的n<15,采用2进制进行压缩,1表示已完成,0表示未完成。若有3门作业,那么状态110,则表示,第1,2门作业完成,第3门作业未完成,映射为10进制数则为"6"。状态"6"对应有两种不同完成作业的顺序,一种,先完成第1门,再完成第2门。另一种,先完成第2门,再完成第1门。搜索过程都取最优解。题目要求若存在多种方案,要按字典序最小的输出,又因为题目输入的是用字典序升序输入,所以对于同样的状态state,若他们有同样的状态值hash[state],先搜索到的字典序肯定比后搜索到的字典序小。所以在更新最优解的时候,只需要用严格"<"号来判断是否更新最优解即可保证多个方案下能得到字典序最小的。

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

const int MAXN = 32768 + 100;
const int INF = 0x3fffffff;

int hash[MAXN];
int pow[17] = {0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384};
int n;
int temp[20]; //记录临时方案
int used[20];
int save[20]; //记录最终方案
int ans;

struct Homework
{
string name;  //课程名
int deadline; //截止时间
int days;     //完成作业需要的天数
};

Homework hw[16];

void init()
{
memset(hash,-1,sizeof(hash));
memset(used,0,sizeof(used));
ans = INF;
}

//参数:编号为k的作业,完成k号作业的hash状态,完成k号作业后的日期now,被扣除的学分sum,完成了cnt门作业
void dfs(int k,int state, int now, int sum, int cnt)
{
if(cnt == n)  //完成全部的作业
{
if(sum < ans) //如果用"<="取代"<",那么输出的结果就不一定是字典序最小的顺序
{
ans = sum;
for(int i=0; i<n; i++)  //保存最优解
{
save[i] = temp[i];
}
return ;
}
}
if(hash[state] != -1 && sum > hash[state])  //最优解剪枝
{
return ;
}
if(hash[state] == -1 || sum < hash[state])  //更新最优解
{
hash[state] = sum;
}
for(int i=1; i<=n; i++)  //遍历所有作业
{
if(!used[i])
{
int tempNow,tempSum;  //回溯后需要恢复now和temp,所以在这里我用多2个新变量,而不去改变now和temp的值
if(now + hw[i].days > hw[i].deadline)
{
tempSum = sum + now + hw[i].days - hw[i].deadline;
}
else
{
tempSum = sum;
}
tempNow = now + hw[i].days;
used[i] = 1;
temp[cnt] = i;
dfs(i,state+pow[i],tempNow,tempSum,cnt+1);
used[i] = 0;	//回溯解除标记
}
}
}

int main()
{
int t;
int i;
cin>>t;
while(t--)
{
init();
cin>>n;
for(i=1; i<=n; i++)
{
cin>>hw[i].name>>hw[i].deadline>>hw[i].days;
}
dfs(0,0,0,0,0);
cout<<ans<<endl;
for(i=0; i<n; i++)
{
cout<<hw[save[i]].name<<endl;
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: