首页 > 代码库 > UVA 11691 - Allergy Test(状压dp+贪心)

UVA 11691 - Allergy Test(状压dp+贪心)

题目链接:11691 - Allergy Test

题意:这题题意看了老半天都没弄懂,好在后面找到个PPT,上面有中文题意- -,不过上面的做法是纯贪心,挺巧妙的但是感觉有点不靠谱,
下载地址:http://par.cse.nsysu.edu.tw/~advprog/advprog2011/11691.ppt
N種過敏原的存活期,每天可把一種過敏原注入人體內。若有兩個以上過敏原存活於人體中,則無法進行實驗(也就是每種過敏原都必須有一天是單獨存活於人體中)。實驗結束於最後的過敏原死亡的那天,求最短實驗天數。
思路:我的思路是状态压缩dp+贪心,20个过敏原做状态压缩,然后每次加过敏原的时候,尽量往里面覆盖,dp[s][k],s表示过敏原使用状态,k表示后面通出来单独存在过敏原的天数,然后选一个新的过敏原去尽量覆盖他,这样k的一维只要开到7就够了,因为每段长度最多就是7。状态转移方程为:
dp[k][s] = min{dfs(s^(1<<i), max(0, num[i] - k - 1)) + max(1, num[i] - k)}
代码:
#include <stdio.h>
#include <string.h>
#include <map>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
const int N = 25;
const int M = (1<<20) + 5;
int t, n, num[N], dp[M][8];

int dfs(int s, int k) {
    if (dp[s][k] != -1) return dp[s][k];
    dp[s][k] = INF;
    if (s == (1<<n) - 1) return dp[s][k] = 0;
	int vis[8];
	memset(vis, 0, sizeof(vis));
    for (int i = 0; i < n; i++) {
		if (vis[num[i]]) continue;
        if (s&(1<<i)) continue;
		vis[num[i]] = 1;
        int t = dfs(s^(1<<i), max(0, num[i] - k - 1)) + max(1, num[i] - k);
        dp[s][k] = min(dp[s][k], t);
    }
    return dp[s][k];
}

int main() {
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
		memset(dp, -1, sizeof(dp));
        for (int i = 0; i < n; i++)
            scanf("%d", &num[i]);
        printf("%d\n", dfs(0, 0));
    }
    return 0;
}