方格取数(1)
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7997 Accepted Submission(s): 3012
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
Author
ailyanlu
Source
题目大意:
如题。
思路:
状态: dp [ i ] [ j ] 代表 i 行 状态 为 j 的时候最大值。
初值: dp [ 1 ] [ j ] = 当前所选的状态之 和 比如 样例 如果我们 选择 1 0 1 那么 dp [ 1 ] [ 1 0 1 ] = 96
状态转移方程: 如果 第 i 行的 状态 j 和第 i-1 行的状态 k 不冲突 那么,dp [ i ] [ j ] = 所有 与 状态 j 不冲突的 最大 dp [ i - 1] [ k ] 值 + 状态 j 的值。
同样是枚举状态 枚举当前行 枚举前一行 。
感想:
这道题写起来很顺利,因为和前一道题是同一种套路。
AC代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxx=1<<15+1;
int n,m;
int mapp[25][25];
int all[maxx];
int dp[21][maxx];
int the_ans(int k,int hh)
{
int tt;
int sum=0;
for(int i=0;i<m;i++)
{
tt=1<<i;
if((all[k]&tt))
{
sum+=mapp[hh][i+1];
}
}
return sum;
}
int main()
{
int i,j,t;
while(~scanf("%d",&n))
{
m=n;
int k=0;
memset(mapp,0,sizeof(mapp));
memset(dp,0,sizeof(dp));
memset(all,0,sizeof(all));
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf("%d",&t);
mapp[i][j]=t;
}
}
for(i=0;i<(1<<m);i++)
{
if((i&(i<<1))==0)
{
all[k++]=i;
}
}
for(i=0;i<k;i++)
{
dp[1][i]=the_ans(i,1);
}
int zmax=0;
for(i=2;i<=n;i++)
{
for(j=0;j<k;j++)
{
zmax=0;
for(int kkk=0;kkk<k;kkk++)
{
if(!(all[j]&all[kkk]))
{
zmax=max(dp[i-1][kkk],zmax);
}
}
dp[i][j]+=zmax;
dp[i][j]+=the_ans(j,i);
}
}
int ans=0;
for(i=0;i<k;i++)
{
ans=max(dp[n][i],ans);
}
cout<<ans<<endl;
}
}