hdu 1565 方格取数(1)
方格取数(1)
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3799 Accepted Submission(s): 1453
Problem Description
给你一个n*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。
Input
包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20)
Output
对于每个测试实例,输出可能取得的最大的和
Sample Input
3
75 15 21
75 15 28
34 70 5
Sample Output
188
Author
ailyanlu
Source
Happy 2007
Recommend
8600
1 //703MS 2056K 1378 B C++ 2 /* 3 4 题意: 5 中文... 6 7 状态压缩: 8 dp[i][j]表示前i行状态j的最优解 9 先预处理出符合条件的数,17000+个(n在20以内), 10 然后进行求解,具体看注释 11 12 */ 13 #include<stdio.h> 14 #include<string.h> 15 #define N 18000 16 int dp[25][N]; 17 int g[25][25]; 18 int st[N],n; 19 int Max(int a,int b) 20 { 21 return a>b?a:b; 22 } 23 int judge(int x) //预处理的判断 24 { 25 int end=0; 26 while(x){ 27 if(end && (x&1)) return 0; 28 end=x&1; 29 x>>=1; 30 } 31 return 1; 32 } 33 int main(void) 34 { 35 int K=0; 36 for(int i=0;i<(1<<20);i++) //预处理 37 if(judge(i)) st[K++]=i; 38 while(scanf("%d",&n)!=EOF) 39 { 40 if(n==0){ 41 puts("0");continue; 42 } 43 int n0=1<<n; 44 memset(dp,0,sizeof(dp)); 45 for(int i=0;i<n;i++) 46 for(int j=0;j<n;j++) 47 scanf("%d",&g[i][j]); 48 int maxn=-1; 49 for(int i=0;st[i]<n0;i++){ //第一行先处理 50 for(int j=0;j<n;j++){ 51 if(st[i]&(1<<j)) 52 dp[0][i]+=g[0][j]; 53 } 54 maxn=Max(maxn,dp[0][i]); 55 } 56 for(int i=1;i<n;i++){ //处理后n-1行 57 for(int j=0;st[j]<n0;j++){ //枚举预处理出来的状态 58 int temp=0; 59 for(int k=0;k<n;k++) 60 if(st[j]&(1<<k)) temp+=g[i][k]; 61 for(int k=0;st[k]<n0;k++) 62 if(!(st[j]&st[k])) //符合没公共边的条件就进行比较 63 dp[i][j]=Max(dp[i][j],temp+dp[i-1][k]); 64 maxn=Max(maxn,dp[i][j]); 65 } 66 } 67 printf("%d\n",maxn); 68 } 69 return 0; 70 } 71 72