题目链接: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; }
UVA 11691 - Allergy Test(状压dp+贪心),码迷,mamicode.com
时间: 2024-10-08 05:50:02