HDU 3811 炮兵阵地
题意:
中文题
http://poj.org/problem?id=1185
算法:
N <= 100;M <= 10。
枚举每行状态,1表示该行放炮兵,0表示不放,相邻两位不能有1,这样的状态才合法
特殊处理第一行,第二行状态。
int cow[110];//保存行状态信息
int num[100]; //保存状态数
int sum[100]; //保存状态对应的1,即炮兵数
int dp[110][64][64]; //dp方程, dp[i][j][k]表示第i行状态为j,上一行状态为k
枚举后面的行。由前往后推,num[i]&num[j] == 0 num[i]&num[k] == 0 num[j]&num[k] == 0
View Code
#include<stdio.h> #include<string.h> #include<stdlib.h> int cow[110];//保存行状态信息 int num[100]; //保存状态数 int sum[100]; //保存状态对应的1,即炮兵数 int dp[110][64][64]; //dp方程, dp[i][j][k]表示第i行状态为j,上一行状态为k int N, M, len; //N行M列 //预处理,求出所有状态 void pre( ) { len = 1; for( int i = 0; i < (1<<M); i++) { int ans = i; if( (i&(ans<<1)) || (i&(ans<<2))) //使其合法 continue; num[len] = i; sum[len] = ans&1; while( ans ) { ans >>= 1; sum[len] += ans&1; } len++; } } //判断状态是否合法,即状态为1的地方,在地图上应该为平原,如果状态为1的地方,地图上为山地则返回false bool jugde( int state, int mp) { for( int i = 1; i < ( 1 << M); i = i << 1) { if( (state & i) && ((mp & i) == 0) ) return false; } return true; } int main( ) { char str[110][20]; while( scanf("%d%d", &N, &M) != EOF) { pre( ); for( int i = 1; i <= N; i++) scanf("%s",&str[i]); memset(cow, 0,sizeof(cow)); for( int i = 1; i <= N; i++) { for( int j = 0; j < M; j++) { if( str[i][j] == 'P' ) cow[i] += (1<<j); } } memset(dp, 0, sizeof(dp)); //处理第一行 for( int i = 1; i < len; i++) { if( jugde(num[i], cow[1]) ) { for( int j = 1; j < len; j++) dp[1][i][j] = sum[i]; } } //处理第二行 for( int i = 1; i < len; i++) { if( jugde(num[i], cow[2]) ) { for( int j = 1; j < len; j++) { for( int k = 1; k < len; k++) { if( ( (num[i]&num[j]) == 0 ) && dp[1][j][k] + sum[i] > dp[2][i][j] ) dp[2][i][j] = dp[1][j][k] + sum[i]; } } } } //对其后面的若干行,状态转移 for( int n = 3; n <= N; n++) for( int i = 1; i < len; i++) for( int j = 1; j < len; j++) { if( jugde(num[i],cow[n]) ) { for( int k = 1;k < len; k++) { if( ((num[i]&num[j]) == 0 ) && ((num[j]&num[k]) == 0 ) && ((num[i]&num[k]) == 0 )) { if( dp[n][i][j] < dp[n-1][j][k] + sum[i] ) dp[n][i][j] = dp[n-1][j][k] + sum[i]; } } } } int ans = 0; for( int i = 1; i < len; i++) for( int j = 1; j < len; j++) if( dp[N][i][j] > ans) ans = dp[N][i][j]; printf("%d\n",ans); } return 0; }
总结下状态压缩算法:
0.判断该题是否可以用状态压缩,
1.选择表示表示状态方法,含义,2进制,3进制,。。。。。定义DP方程,含义
2。根据题意,预处理合法状态
3.特殊处理边界条件
4.从前往后推,枚举所有状态,满足相应题目要求
5.数据量大的要用矩阵优化,记忆化搜索
6.输出最优解
posted on 2012-08-06 16:29 more think, more gains 阅读(258) 评论(0) 编辑 收藏 举报