http://acm.hdu.edu.cn/showproblem.php?pid=2167
第一道状态压缩dp,其实就是爆搜,只不过把排除了大量不可能的情况,先用sta保存每行可能的情况,sum[i][j]保存i行j种情况的该行和,然后依次更新dp。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int n,sum[20][1<<15],dp[20][1<<15],a[20][20],sta[1<<15]; int main() { while(~scanf("%d",&a[1][1])) { n = 1; char c; while(~scanf("%d%c",&a[1][++n],&c) && c != ' '); for(int i = 2;i <= n;i++) { for(int j = 1;j <= n;j++) scanf("%d",&a[i][j]); } memset(dp,0,sizeof(dp)); memset(sum,0,sizeof(sum)); int cnt = 0,endd = 1<<n; for(int i = 0;i < endd;i++) { if(i & (i << 1)) continue; sta[++cnt] = i; } for(int i = 1;i <= n;i++) { for(int j = 1;j <= cnt;j++) { for(int k = 1;k <= n;k++) { if(sta[j] & (1<<(k-1))) sum[i][j] += a[i][k]; } } } for(int i = 1;i <= cnt;i++) dp[1][i] = sum[1][i]; for(int i = 1;i < n;i++) { for(int j = 1;j <= cnt;j++) { for(int k = 1;k <= cnt;k++) { if(sta[j] & sta[k]) continue; if(sta[j] & (sta[k]<<1)) continue; if(sta[j] & (sta[k]>>1)) continue; dp[i+1][k] = max(dp[i+1][k],dp[i][j]+sum[i+1][k]); } } } int ans = 0; for(int i = 1;i <= cnt;i++) ans = max(ans,dp[n][i]); printf("%d ",ans); } return 0; }