您的位置:首页 > 其它

方格取数(1) (状态dp)

2017-12-10 21:02 155 查看
给你一个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


题目大概:

给出一个n*n大小的矩阵,找出给矩阵内的最大和,要求这些数之间不能相邻。

思路:

与种玉米很像。

不过每一个位置多了一个状态,这就即需要预处理出所有的符合条件的状态,又需要预处理出每一行状态的和。

主要是预处理太麻烦。

dp【i】【j】就是到第i行时j状态时的最大和。

方程dp[i][j]=max(dp[i][j],dp[i-1][k]+stt[i][j]);

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int ma=22;
const int mm=21000;
int st[mm];
int stt[ma][mm],dp[ma][mm],map[ma][ma];
int cnt;

void find(int n)
{
int sum=1<<n;
cnt=1;
for(int i=0;i<sum;i++)//枚举状态
{
if((i&(i<<1))==0)//判断给状态两个1之间不能挨着
{
st[cnt++]=i;//符合条件记录状态
}
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(st,0,sizeof(st));
memset(stt,0,sizeof(stt));
memset(dp,0,sizeof(dp));
cnt=0;
find(n);//预处理
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&map[i][j]);
}
}
for(int i=1;i<=n;i++)//枚举每一行
{
for(int j=1;j<=cnt;j++)//枚举每一个状态
{
int sum=n;
for(int k=1;k<(1<<n);k=(k<<1))//计算出该状态的和
{
if((k&st[j])!=0)
{
stt[i][j]+=map[i][sum];
}
sum--;
}
}
}
for(int i=1;i<=cnt;i++)//更新第一行
{
dp[1][i]=stt[1][i];
}
for(int i=2;i<=n;i++)//枚举行
{
for(int j=1;j<=cnt;j++)//枚举状态
{
for(int k=1;k<=cnt;k++)//枚举前一个状态
{
if((st[j]&st[k])==0)//两个状态不能有挨着的元素
{
dp[i][j]=max(dp[i][j],dp[i-1][k]+stt[i][j]);
}
}
}
}
int sum=0;
for(int i=1;i<=cnt;i++)
{
sum=max(sum,dp
[i]);
}
printf("%d\n",sum);

}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息