HDU 4049 Tourism Planning(狀態壓縮)
阿新 • • 發佈:2018-12-14
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int const INF = 0x3fffffff; int n, m; //dp[i][s]表示經過前i個城市時,狀態為s的總bonus的值,狀態s表示n個人在或不在的狀態 int dp[11][(1 << 11)], c[11][(1 << 11)]; int v[11][11], b[11][11], p[11]; void cal() { for(int i = 1; i <= m; i++) { //景點 for(int s = 0; s < (1 << n); s++) { //狀態 c[i][s] = 0; //初始化為0 for(int j = 0; j < n; j++) { //經過前i個景點第j個人在的狀態 if(s & (1 << j)) { //值=喜愛程度-花費 c[i][s] += v[j][i] - p[i]; //若在第j個人在的狀態下,其前的第k個人也在 //則說明他們必然同時去了前i個景點,加上額外值 for(int k = 0; k < j; k++) if(s & (1 << k)) c[i][s] += b[k][j]; } } } } } int main() { freopen("data.in", "r", stdin); while(scanf("%d %d", &n, &m) != EOF && (n + m)) { for(int i = 1; i <= m; i++) scanf("%d", &p[i]); //到每個景點的花費 for(int i = 0; i < n; i++) for(int j = 1; j <= m; j++) scanf("%d", &v[i][j]); //每個人到對每個景點的喜愛程度 for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) scanf("%d", &b[i][j]); //同一個地點多個人去的喜愛度額外值 cal(); //預處理,計算每個城市每種狀態下的值 //初始化dp for(int i = 1; i <= m; i++) for(int s = 0; s < (1 << n); s++) dp[i][s] = -INF; int ans = -INF; // 寫法1: // for(int i = 1; i <= m; i++) //景點 // for(int s = 0; s < (1 << n); s++) //當前狀態s // for(int j = (1 << n) - 1; j >= s; j--) //s之後的所有狀態,因為人走了就不能回來 // if((j & s) == s) //若當前狀態是之前某個狀態的子狀態 // //相當於揹包,經過前i個城市,狀態為s的值可能由經過前i-1個城市狀態為j // //(j-> s:有人離開)的值加上經過第i個城市狀態為s的值 // dp[i][s] = max(dp[i][s], dp[i - 1][j] + c[i][s]); // 寫法2: for(int i = 1; i <= m; i++) for(int s = 0; s < (1 << n); s++) { for(int j = s; ; j = ((j - 1) & s)) {//列舉子集 if(j == 0) { //向前列舉到0 dp[i][0] = max(dp[i][0], dp[i - 1][s] + c[i][0]); break; } //列舉s的子狀態(s -> j有人離開),與寫法1正好相反 dp[i][j] = max(dp[i][j], dp[i - 1][s] + c[i][j]); } } //求遊覽m個景點下的最大值 for(int s = 0; s < (1 << n); s++) ans = max(ans, dp[m][s]); if(ans <= 0) printf("STAY HOME\n"); else printf("%d\n", ans); } }