您的位置:首页 > 其它

HDU 1074 Doing Homework 状压DP

2016-03-24 21:11 357 查看
被水题卡了三个点,真是不开心...

题目链接:Doing Homework

思路:全排列枚举所有的状态,找出哪种状态时减少的人数最少,状态最多是2^15-1。不到40000,不会超时。然后为了节省空间,可以用状压DP,以一个16位的十进制数的第0位,第1位...第n-1为的0或1分别表示第1项,第2项和第n项任务未完成或已完成。因为要输出路径,所以保存每个的前驱,输出路径时,dp[i].pre^i = j 得到的j是从dp[i].pre状态完成j任务时到了i状态。

感觉状压DP就是普通的DP加上位运算,目前这么感觉。而且多用于暴力枚举?大概吧。

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <math.h>
#define maxn 1<<16
using namespace std;

struct Task {
char name[210];
int dead;
int cost;
}task[210];

struct Dp {
int pre;
int cost;
int resco;
}dp[maxn];

bool vis[maxn];

void out(int now) {
if (dp[now].pre == 0) {
int cnt = 0;
while(now > 0) {
cnt++;
now /= 2;
}
cout << task[cnt-1].name << endl;
return;
}
else if (dp[now].pre != 0) {
int pre = dp[now].pre;
int cur = (pre ^ now); // 得到的是由上一步到这一步完成的任务。
out(pre);
int cnt = 0;

while(cur > 0) {
cnt++;
cur /= 2;
}
cout << task[cnt-1].name << endl; // 输出这步任务的名字
return;
}
}

int main() {
int t;
int n;
cin >> t;
while(t--) {
cin >> n;
for (int i=0; i<n; ++i) {
cin >> task[i].name >> task[i].dead >> task[i].cost;
}

int upstu = (1<<n)-1; // 状态数上限
memset(vis, 0, sizeof(vis));
memset(dp, 0, sizeof(dp));
// init
dp[0].pre = -1;
dp[0].cost = 0;
dp[0].resco = 0;
vis[0] = 1;

int now, nxt;
for (int stu=0; stu<upstu; ++stu) { // 遍历所有状态
for (int work=0; work<n; ++work) { // 遍历当前状态下的所有任务
now = (1<<work);

if ((now & stu) == 0) { // 任务没做
nxt = (now | stu);

//计算当前状态下完成该任务需要的时间和会有的罚时
int tcost = dp[stu].cost + task[work].cost;
int tresco = 0;
if (tcost > task[work].dead) {
tresco = tcost - task[work].dead;
}

tresco += dp[stu].resco; // 这句不能加在两个if里,因为比较的扣分数就是这一段时间的所有扣分数。

if (!vis[nxt]) { // 如果这种状态没有出现过
dp[nxt].cost = tcost;
//dp[nxt].resco = (tresco + dp[stu].resco);
dp[nxt].resco = tresco;
dp[nxt].pre = stu;
vis[nxt] = 1;
}
else { // 如果出现过
if (dp[nxt].resco > tresco) { //选择扣分数较少的
//dp[nxt].resco = (tresco + dp[stu].resco);
dp[nxt].resco = tresco;
dp[nxt].cost = tcost;
dp[nxt].pre = stu;
}
}
}
}
}
cout << dp[upstu].resco << endl;
out(upstu);
}
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: