HDOJ 4049 Tourism Planning(状态压缩DP)
2014-03-05 21:08
288 查看
题意:N (N≤10)个人按照已经定好的顺序参观M(M≤10)个景点,每个景点都有花费
c,每个人对每个景点有一个喜欢的程度值 a,每两个人之间有一个喜欢的程度值 b,如果他们一起参观某个景点会产生。每个人都可以中途推出旅行,求使得 a + b - c 最大的方案的值。
dp[i][s]代表参观到第 i 个景点,剩下的人集合为 s 所能得到的最大值。
dp[i][s] = max(dp[i-1][s1]) + value(i,s)
s 是 s1 的子集,value 代表在景点 i 获得的值。
枚举子集:
for(int s1 = s; s1 >= 0; s1 = (s1-1)&s) {//枚举子集
//solve
if(s1 == 0) break;//没有这句死循环
}
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 10, inf = 0x3f3f3f3f;
int cost[maxn], sin[maxn][maxn], bon[maxn][maxn];
int dp[maxn][1<<maxn];
bool vis[maxn][1<<maxn];
int n, m;
int main()
{
while(~scanf("%d%d", &n, &m) && n) {
for(int i = 0; i < m; i++) scanf("%d", &cost[i]);
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
scanf("%d", &sin[i][j]);
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
scanf("%d", &bon[i][j]);
int all = 0;
memset(dp, 0, sizeof(dp));
memset(vis, 0, sizeof(vis));
for(int i = 0; i < n; i++) all += (1<<i);
for(int i = 0; i < m; i++) {
for(int s = all; s >= 0; s = (s-1)&all) {
for(int j = 0; j < n; j++) {//感觉这里还是有些重复工作,是否可以利用矩阵乘法的方式直接求dp[0][s]
if(s & (1<<j)) {
dp[i][s] += sin[j][i] - cost[i];
for(int k = 0; k < n; k++) {
if(j == k) break;
if(s & (1<<k)) dp[i][s] += bon[j][k];
}
}
}
if(i != m-1) {
for(int s1 = s; s1 >= 0; s1 = (s1-1)&s) {//枚举子集
if(!vis[i+1][s1]) {
dp[i+1][s1] = dp[i][s];
vis[i+1][s1] = 1;
}
else dp[i+1][s1] = max(dp[i+1][s1], dp[i][s]);
if(s1 == 0) break;
}
}
if(s == 0) break;//没有这条会死循环
}
}
int ans = dp[m-1][0];
for(int s = all; s; s = (s-1)&all)
ans = max(ans, dp[m-1][s]);
if(ans > 0) printf("%d\n", ans);
else printf("STAY HOME\n");
}
return 0;
}
c,每个人对每个景点有一个喜欢的程度值 a,每两个人之间有一个喜欢的程度值 b,如果他们一起参观某个景点会产生。每个人都可以中途推出旅行,求使得 a + b - c 最大的方案的值。
dp[i][s]代表参观到第 i 个景点,剩下的人集合为 s 所能得到的最大值。
dp[i][s] = max(dp[i-1][s1]) + value(i,s)
s 是 s1 的子集,value 代表在景点 i 获得的值。
枚举子集:
for(int s1 = s; s1 >= 0; s1 = (s1-1)&s) {//枚举子集
//solve
if(s1 == 0) break;//没有这句死循环
}
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 10, inf = 0x3f3f3f3f;
int cost[maxn], sin[maxn][maxn], bon[maxn][maxn];
int dp[maxn][1<<maxn];
bool vis[maxn][1<<maxn];
int n, m;
int main()
{
while(~scanf("%d%d", &n, &m) && n) {
for(int i = 0; i < m; i++) scanf("%d", &cost[i]);
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
scanf("%d", &sin[i][j]);
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
scanf("%d", &bon[i][j]);
int all = 0;
memset(dp, 0, sizeof(dp));
memset(vis, 0, sizeof(vis));
for(int i = 0; i < n; i++) all += (1<<i);
for(int i = 0; i < m; i++) {
for(int s = all; s >= 0; s = (s-1)&all) {
for(int j = 0; j < n; j++) {//感觉这里还是有些重复工作,是否可以利用矩阵乘法的方式直接求dp[0][s]
if(s & (1<<j)) {
dp[i][s] += sin[j][i] - cost[i];
for(int k = 0; k < n; k++) {
if(j == k) break;
if(s & (1<<k)) dp[i][s] += bon[j][k];
}
}
}
if(i != m-1) {
for(int s1 = s; s1 >= 0; s1 = (s1-1)&s) {//枚举子集
if(!vis[i+1][s1]) {
dp[i+1][s1] = dp[i][s];
vis[i+1][s1] = 1;
}
else dp[i+1][s1] = max(dp[i+1][s1], dp[i][s]);
if(s1 == 0) break;
}
}
if(s == 0) break;//没有这条会死循环
}
}
int ans = dp[m-1][0];
for(int s = all; s; s = (s-1)&all)
ans = max(ans, dp[m-1][s]);
if(ans > 0) printf("%d\n", ans);
else printf("STAY HOME\n");
}
return 0;
}
相关文章推荐
- hdoj 1074 Doing Homework 【状态压缩dp】
- HDOJ 1755 - A Number Puzzle 排列数字凑同余,状态压缩DP
- hdoj1074 Doing Homework(好题呀,状态压缩+DP)
- HDOJ 4529 - N骑士问题 状态压缩DP
- HDOJ 1081 To The Max(dp)(状态压缩)未解决
- 20140930 【 DP - 状态压缩 】 2014-上海区域赛-网络预选赛 hdoj 5045 Contest
- HDOJ 4057 - Rescue the Rabbit 简单的AC自动机+状态压缩DP
- HDU 4049 状态压缩DP
- HDOJ 2442 -bricks 六进制状态压缩DP 一直TLE.打表过的..
- HDOJ4336Card Collector【概率dp求期望+状态压缩】
- HDOJ 1074.Doing Homework(状态压缩DP)
- hdoj 5045 (dp 状态压缩)
- HDOJ 4310 - Hero 简单的状态压缩DP
- 【最短路+状态压缩DP】 HDOJ 4856 Tunnels
- HDOJ 2640 - Toy bricks 状态压缩DP
- HDOJ-3427 & ZOJ-3190 Resource Archiver AC自动机压缩状态DP..
- HDOJ 5067Harry And Dig Machine(状态压缩DP)
- hdoj 5125 Little Zu Chongzhi's Triangles【状态压缩dp】
- HDOJ 1400 & POJ 2411 - Mondriaan's Dream 状态压缩DP
- HDU 4049 Tourism Planning 状态压缩(DP)