车 II 题解
题目
有一个 n n n m m m的棋盘( n n n、 m m m≤80, n n n m m m≤80)要在棋盘上放 k k k( k k k≤20)个棋子,使得任意两个棋子不相邻。求合法的方案总数。
输入
n n n, m m m, k k k
输出
方案总数
样例
input
3 3 2
output
24
解题思路
先找出小的作为列
再枚举出所有状态
要对第一行赋初值
第一重循环枚举行
第二重循环枚举当前状态
第三重循环枚举上一行状态
第四重循环枚举士兵数
代码
#include<iostream>
#include<cstdio>
using namespace std;
struct hhx{
int t,s;
}a[1<<10];
int n,m,v,x,f[10][1<<9][30],ans,t;
void dfs(int dz,int dw,int ds)
{
if (dw>n)
{
a[++t].t=dz;
a[t].s=ds;
return;
}
dfs(dz,dw+1,ds);
dfs(dz+(1<<(dw-1)),dw+2,ds+1);
}
int main()
{
scanf("%d%d%d",&n,&m,&v);
if (n>m)
{
x=n;
n=m;
m=x;
} //小的做列
dfs(0,1,0); //枚举出所有状态
for (int i=1;i<=t;i++)
f[1][a[i].t][a[i].s]=1; //赋初值
for (int i=2;i<=m;i++)
for (int j=1;j<=t;j++)
for (int k=1;k<=t;k++)
if (!(a[j].t & a[k].t))
for (int r=0;r<=v;r++)
if (r>=a[j].s) f[i][a[j].t][r]+=f[i-1][a[k].t][r-a[j].s]; //DP转移
for (int i=1;i<=t;i++)
ans+=f[m][a[i].t][v];
cout<<ans<<endl;
return 0;
}