I - 方格取数(1)
Crawling in process... Crawling failed Time Limit:5000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
Submit Status
Description
Input
Output
Sample Input
Sample Output
Hint
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
思路:
先算出一行的每个dp,然后枚举以后的每一行,他的dp就是他加上上一行中不冲突的最大的那个dp.第二道状态压缩DP,还是参照了别人的博客,写了这两个状压DP,已经对状压DP理解了很多了,下一道题可以自己做了。(下面说的C题是上一篇博客的题)
代码:
1 #include<iostream> 2 #include<string> 3 #include<cstdio> 4 #include<cmath> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<iomanip> 9 #include<queue> 10 using namespace std; 11 int n,sn; 12 int dp[25][1<<13]; //这里就不需要dp[25][1<<20]了,只要能满足sn的大小就行 13 int map[25][25]; 14 int sta[1<<13]; 15 int max(int x,int y) 16 { 17 return x>y?x:y; 18 } 19 void init() 20 { 21 sn=0; //用sn代替(1<<n)表示状态会节省内存和时间,(1<<n)的方法参见C题 22 for(int i=0;i<(1<<n);i++) 23 { 24 if(i&(i<<1)) continue; 25 sta[sn++]=i; //记录互不相邻的数 26 } 27 } 28 int insum(int a,int b) 29 { 30 int sum=0,j=n; 31 while(b) 32 { 33 if(1&b) 34 sum+=map[a][j]; 35 j--; 36 b=b>>1; 37 } 38 return sum; 39 } 40 int main() 41 { 42 while(scanf("%d",&n)!=EOF) 43 { 44 memset(dp,0,sizeof(dp)); 45 for(int i=1;i<=n;i++) 46 for(int j=1;j<=n;j++) 47 scanf("%d",&map[i][j]); 48 init(); 49 for(int i=0;i<sn;i++) 50 dp[1][i]=insum(1,sta[i]); //这里这里直接用dp[1][i]而不是dp[1][sta[i]],会节省时间与内存 51 for(int i=2;i<=n;i++) 52 { 53 for(int j=0;j<sn;j++) 54 { 55 int tem=insum(i,sta[j]); 56 for(int k=0;k<sn;k++) 57 { 58 if((sta[j]&sta[k])) continue; //判断与上一行状态有没有相邻的数 59 dp[i][j]=max(dp[i][j],dp[i-1][k]+tem); 60 } 61 } 62 } 63 int sum=0; 64 for(int i=0;i<sn;i++) 65 sum=max(dp[n][i],sum); //最后求这一行中的最大的,因为一行中的每一个dp值 66 //已经加上了本行与其不相邻的数 67 printf("%d\n",sum); 68 } 69 return 0; 70 }
时间: 2024-10-08 11:13:23