题意:
给定一个n*n (n<=20) 的方格,里头放有一些非负数,选择一些不相邻的格子,使其和最大。
分析:
主要思想是从第一行到第N行,从第一列到第N列进行DP,用位来保存状态,比如在i行j列,对所有的0到2^n -1 状态进行计算,最后的结果是从i=n-1,j=n-1的2^n个状态求最大就OK了。别以为这运算量很大,其实只有O(n*n*2^n)比直接暴搜O(n!*n!)快了N多,因为这题数据比较小,N最大为20,所以可以这么DP。但如果N很大的话这种方法显然不行,那就要用到最大流了。
1#include<iostream>
2using namespace std;
3
4const int mm=1<<20+1;
5int rect[51][51];
6int dp[2][mm];
7int maxn=-1;
8int n;
9
10int solve()
11{
12 int i,j,k,p,t,z;
13 for(i=0;i<n;i++)
14 {
15 for(j=0;j<n;j++)
16 {
17 t=1<<j;
18 p=(i*n+j)%2;
19 for(k=0;k<(1<<n);k++)
20 {
21 if((k&t)==0)
22 dp[1-p][k]=dp[p][k]>dp[p][k+t]? dp[p][k]:dp[p][k+t];
23 else if(j>0&&(k&(t>>1)))dp[1-p][k]=0;
24 else dp[1-p][k]=dp[p][k-t]+rect[i][j];
25 }
26 }
27 }
28 return 0;
29}
30
31int main()
32{
33 int i,j;
34 while(EOF!=scanf("%d",&n))
35 {
36 for(i=0;i<n;i++)
37 for(j=0;j<n;j++)
38 scanf("%d",&rect[i][j]);
39 maxn=-1;
40 memset(dp,0,sizeof(dp));
41 solve();
42 for(i=0;i<(1<<n);i++)
43 {
44 if(dp[(n*n)%2][i]>maxn)
45 maxn=dp[(n*n)%2][i];
46 }
47 printf("%d\n",maxn);
48 }
49 return 0;
50}