HDU 1565 状态压缩
题意:
你一个n*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。(n <= 20)
算法:
因为n比较少20,可以用状态压缩,1表示方格该数取,0表示不取。
每一行的状态有1<<N种,先预处理所有合法状态,即相邻两位不能为1,
判断条件是i && (i<<1),下一行的状态要满足条件的是跟上一行没有相
邻的 num[i] & num[j] == 0
int num[21000]; //状态
int sum[21][21000]; //该状态的和
int len;
int mt[30][30]; //存储方格
View Code
#include<stdio.h> #include<string.h> #include<stdlib.h> int num[21000]; //状态 int sum[21][21000]; //该状态的和 int len; int mt[30][30]; //存储方格 int N; int dp[30][21000]; void pre(int N) { len = 0; for( int i = 0; i < (1<<N); i++) { if( i & (i<<1) ) continue; num[len] = i; for( int k = 1; k <= N; k++) { int ans = i; for( int j = N; j > 0; j--) { if( ans&1 ) { sum[k][len] += mt[k][j]; } ans = ans>>1; } } len++; } } int main( ) { while( scanf("%d",&N) != EOF) { memset(sum, 0, sizeof(sum)); for( int i = 1; i <= N; i++) for( int j = 1; j <= N; j++) scanf("%d",&mt[i][j]); pre( N ); memset(dp, 0, sizeof(dp)); dp[0][0] = 0; for( int n = 1; n <= N; n++) for( int i = 0; i < len; i++) for( int j = 0; j < len; j++) { if( (num[i]&num[j]) == 0 ) { if( dp[n][i] < dp[n-1][j] + sum[n][i] ) { dp[n][i] = dp[n-1][j] + sum[n][i]; } } } int ans = 0; for( int i = 0; i < len; i++) if( dp[N][i] > ans ) ans = dp[N][i]; printf("%d\n", ans); } return 0; }
posted on 2012-08-05 09:13 more think, more gains 阅读(191) 评论(0) 编辑 收藏 举报