方格取数(1)
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3600 Accepted Submission(s): 1373
Problem Description
给你一个n*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。
Input
包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20)
Output
对于每个测试实例,输出可能取得的最大的和
Sample Input
3
75 15 21
75 15 28
34 70 5
Sample Output
188
#include<iostream> #include<cstring> #include<string> #include<cstdio> using namespace std; int save[1<<20+1],map[40][40]; int dp[3][1<<20+1],cnt,n; int max1(int a,int b) { return a > b ? a : b; } bool ok(int x) { if( x& (x>>1)) return false; // if(x & (x<<2)) return false; return true; } int getsum(int f,int k) { int ans=0; for(int i=0;i<n;i++) { if(k & (1<<i)) ans+=map[f][i]; } return ans; } bool match(int l,int r) { if(l & r) return false; return true; } int slove() { int i,j,k; for(i=0;i<cnt;i++) { dp[0][i] = getsum(0,save[i]); } for(i=1;i<=n;i++) { for(j=0;j<cnt;j++) { dp[i%2][j] = 0; for(k=0;k<cnt;k++) { if(match(save[j],save[k])) { dp[i%2][j]=max1(dp[i%2][j],dp[(i+1)%2][k]+getsum(i,save[j])); } } } } int ans=0; for( i=0;i<cnt;i++) ans=max1(ans,dp[(n+1)%2][i]); printf("%d\n",ans); return ans; } int main() { //int n; while(~scanf("%d",&n)) { int i,j; memset(dp,0,sizeof(dp)); for(i=0;i<n;i++) { for(j=0;j<n;j++) { scanf("%d",&map[i][j]); } } cnt = 0; for(i=0;i<(1<<n);i++) { if(ok(i)) { save[cnt++] = i; //save[cnt++] = getsum(i); } } slove(); } return 0; }