链接:https://www.nowcoder.com/acm/contest/74/F
来源:牛客网
题目描述
德玛西亚是一个实力雄厚、奉公守法的国家,有着功勋卓著的光荣军史。
这里非常重视正义、荣耀、职责的意识形态,这里的人民为此感到强烈自豪。
有一天他们想去制裁邪恶的比尔吉沃特,于是派遣了自己最优秀的战士。
结果比尔吉沃特领土太小,只有长为n宽为m共计n*m块土地,其中有些土
地标记为0表示为高山峻岭或者深海湖泊,英雄们无法在其中站立,只有标
记为1的土地才能容纳一个英雄。德玛西亚的英雄们战斗时有一个特点,他
们不希望队友站在自己旁边显得很暧昧。请问最多能有多少种安排德玛西
亚英雄的方法?
输入描述:
输入包含多组测试数据;
每组数据的第一行包含2个整数n和m (n <= 12, m <= 12 ),之间用空格隔开;
接下来的n行,每行m个数,表示n*m的比尔吉沃特领土。
输出描述:
输出一个整数n代表安排应用的方法。
(答案取膜100000000)
输入
3 3
1 1 1
0 1 1
1 0 0
输出
24
解题思路
据说是一道状态dp的模板题,找了份模板理解了一下。。。
代码
#include<iostream>
#include<memory.h>
#include<algorithm>
#define mod 100000000
using namespace std;
int n,m,num;
int kind[5000];
int dp[5000][20];
int map[22];//每一行的状态
int main()
{
int i,j,z,x,k,y;
while(cin>>n>>m)
{
memset(map,0,sizeof(map));
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
cin>>x;
if(x==0)
map[i]+=1<<(j-1);
}
memset(dp,0,sizeof(dp));
num=0;
for(i=0;i<=((1<<m)-1);i++)
if((i&(i<<1))==0)
kind[++num]=i;//记录士兵不相邻的站队方式
for(j=1;j<=num;j++)
{
x=kind[j];
if((x&map[1])==0)//第一行可能的站队方式
dp[j][1]=1;
}
for(i=2;i<=n;i++)
for(j=1;j<=num;j++)
{
x=kind[j];
for(k=1;k<=num;k++)
{
y=kind[k];
if((x&y)>0)//第i行和第i-1行相邻
continue;
if((y&map[i])>0)//第i行不能部署该站队方式
continue;
(dp[k][i]+=dp[j][i-1])%=mod;//状态转移方程
}
}
int ans=0;
for(i=1;i<=num;i++)//前n行所有可能的情况
(ans+=dp[i][n])%=mod;
cout<<ans<<endl;
}
return 0;
}