入门级状态压缩dp题。
题意:从方格中取一些数,要求所取位置不相邻(包括对角线相邻),求最大的和。
做法:把每行的状态压缩成二进制数,设状态dp[i][p]为第i行取集合p,容易得出dp[i][p] = max{dp[i-1][q] + cnt[i][p]| 集合p,q可以共存},cnt[i][p]为第i行为集合p时所取得数的和。
View Code
1 /* 2 *Author: Zhaofa Fang 3 *Created time: 2013-03-31-10.33 4 *Language: C++ 5 */ 6 #include <cstdio> 7 #include <cstdlib> 8 #include <sstream> 9 #include <iostream> 10 #include <cmath> 11 #include <cstring> 12 #include <algorithm> 13 #include <string> 14 #include <utility> 15 #include <vector> 16 #include <queue> 17 #include <stack> 18 #include <map> 19 #include <set> 20 using namespace std; 21 22 typedef long long ll; 23 #define DEBUG(x) cout<< #x << ':' << x << endl 24 #define REP(i,n) for(int i=0;i < (n);i++) 25 #define REPD(i,n) for(int i=(n-1);i >= 0;i--) 26 #define FOR(i,s,t) for(int i = (s);i <= (t);i++) 27 #define FORD(i,s,t) for(int i = (s);i >= (t);i--) 28 #define PII pair<int,int> 29 #define PB push_back 30 #define MP make_pair 31 #define ft first 32 #define sd second 33 #define lowbit(x) (x&(-x)) 34 #define INF (1<<30) 35 36 int k; 37 int maz[17][17],dp[2][1600]; 38 int cnt[20][1600]; 39 int s[1600]; 40 bool ok(int x){ 41 if(x&(x<<1))return false; 42 return true; 43 } 44 int fun(int x,int row,int n){ 45 int res=0,j=0; 46 REP(j,n){ 47 if(x&(1<<j))res+=maz[row][j]; 48 } 49 return res; 50 } 51 void pre_deal(int n){ 52 53 memset(s,0,sizeof(s)); 54 memset(cnt,0,sizeof(cnt)); 55 REP(i,(1<<n)){ 56 if(ok(i)){ 57 s[k++] = i; 58 } 59 } 60 REP(i,n){ 61 REP(j,k) 62 cnt[i][j] = fun(s[j],i,n); 63 } 64 } 65 66 int main(){ 67 //freopen("in","r",stdin); 68 //freopen("out","w",stdout); 69 char str[100]; 70 while(gets(str)){ 71 int len = strlen(str); 72 int n=0,res=0; 73 REP(i,len){ 74 if(str[i]>='0'&&str[i]<='9')res = res*10+str[i]-'0'; 75 else { 76 maz[0][n++] = res; 77 res = 0; 78 } 79 } 80 maz[0][n++]=res; 81 FOR(i,1,n-1)REP(j,n)scanf("%d",&maz[i][j]); 82 getchar(); 83 gets(str); 84 k = 0; 85 pre_deal(n); 86 memset(dp,-1,sizeof(dp)); 87 int now = 1; 88 REP(i,k)dp[now][i] = cnt[0][i]; 89 FOR(i,1,n-1){ 90 now ^= 1; 91 REP(p,k){ 92 REP(q,k){ 93 if(s[p]&s[q])continue; 94 if(s[p]&(s[q]<<1))continue; 95 if(s[p]&(s[q]>>1))continue; 96 if(dp[now^1][q]==-1)continue; 97 dp[now][p] = max(dp[now][p],dp[now^1][q]+cnt[i][p]); 98 } 99 } 100 } 101 int ans = 0; 102 REP(i,k)ans=max(ans,dp[now][i]); 103 printf("%d\n",ans); 104 } 105 return 0; 106 }