棋盘上放棋子(任意两个棋子不相邻)
2017-09-08 21:06
295 查看
给出一个 n*m 的棋盘(n 、m≤ 80,n*m ≤ 80),要在棋盘上放 k(k ≤ 20)个棋子, 使得任意两个棋子不相邻。问有多少种方案。
//给出一个 n*m 的棋盘(n 、m≤ 80,n*m ≤ 80),要在棋盘上放 k(k ≤ 20)个棋子,
//使得任意两个棋子不相邻。问有多少种方案。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF=(1<<20)-1;
int f[81][1<<9][21]={0};//第i行状态为s[j],前i行放k个棋子的方案数。
int s[1<<9];//各种状态
int c[1<<9];//每种状态对应得1的个数
int n,m,maxn=0,count1=0,num=0;//n行,m列
//找出一行最多有多少种满足条件的状态
//因为列数少行数多,不考虑题目要求的最多放置棋子数
void dfs(int state,int p,int count1)//当前状态,位置,1的个数
{
if(p>m) //每个格子都放有棋子了
{
num++;
s[num]=state;
c[num]=count1;
return ; //返回上一个位置执行下一种方案。
}
dfs(state,p+1,count1);//当前位置不放
dfs(state+(1<<(p-1)),p+2,count1+1);//当前位置放,放了之后下一个位置就不能放了。
}
int main()
{
int i,j,k,t;
freopen("a.txt","r",stdin);
scanf("%d%d%d",&n,&m,&maxn);
if(m>n) swap(n,m);//让列成为小的那个
dfs(0,1,0);//全不放,从第一列开始,1的个数是0
for(i=1;i<=num;++i) printf("%d ",s[i]); printf(" num:%d\n",num);
for(i=1;i<=num;++i)
f[1][s[i]][c[i]]=1;//第一行使用状态s[i],放了count[i]个棋子。是一种方案
for(i=2;i<=n;++i)//前2-n行
{
for(j=1;j<=num;++j)//当前行的状态
{
for(k=1;k<=num;++k)//上一行状态
{
if(!(s[j]&s[k]))//当前行与上一行不冲突
{
for(t=0;t<=maxn;++t)//前i行放了几个棋子
{
if(t>=c[j])//到当前行为止放的棋子总数要不小于选择当前状态放会添加的棋子数。
f[i][s[j]][t] += f[i-1][s[k]][t-c[j]];
}
}
}
}
}
long long ans=0;
for(i=1;i<=num;++i)
ans+=f
[s[i]][maxn]; //前n行放k个棋子,第n行选择状态s[i]的方案数相加
printf("%I64d",ans);
return 0;
}
//给出一个 n*m 的棋盘(n 、m≤ 80,n*m ≤ 80),要在棋盘上放 k(k ≤ 20)个棋子,
//使得任意两个棋子不相邻。问有多少种方案。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF=(1<<20)-1;
int f[81][1<<9][21]={0};//第i行状态为s[j],前i行放k个棋子的方案数。
int s[1<<9];//各种状态
int c[1<<9];//每种状态对应得1的个数
int n,m,maxn=0,count1=0,num=0;//n行,m列
//找出一行最多有多少种满足条件的状态
//因为列数少行数多,不考虑题目要求的最多放置棋子数
void dfs(int state,int p,int count1)//当前状态,位置,1的个数
{
if(p>m) //每个格子都放有棋子了
{
num++;
s[num]=state;
c[num]=count1;
return ; //返回上一个位置执行下一种方案。
}
dfs(state,p+1,count1);//当前位置不放
dfs(state+(1<<(p-1)),p+2,count1+1);//当前位置放,放了之后下一个位置就不能放了。
}
int main()
{
int i,j,k,t;
freopen("a.txt","r",stdin);
scanf("%d%d%d",&n,&m,&maxn);
if(m>n) swap(n,m);//让列成为小的那个
dfs(0,1,0);//全不放,从第一列开始,1的个数是0
for(i=1;i<=num;++i) printf("%d ",s[i]); printf(" num:%d\n",num);
for(i=1;i<=num;++i)
f[1][s[i]][c[i]]=1;//第一行使用状态s[i],放了count[i]个棋子。是一种方案
for(i=2;i<=n;++i)//前2-n行
{
for(j=1;j<=num;++j)//当前行的状态
{
for(k=1;k<=num;++k)//上一行状态
{
if(!(s[j]&s[k]))//当前行与上一行不冲突
{
for(t=0;t<=maxn;++t)//前i行放了几个棋子
{
if(t>=c[j])//到当前行为止放的棋子总数要不小于选择当前状态放会添加的棋子数。
f[i][s[j]][t] += f[i-1][s[k]][t-c[j]];
}
}
}
}
}
long long ans=0;
for(i=1;i<=num;++i)
ans+=f
[s[i]][maxn]; //前n行放k个棋子,第n行选择状态s[i]的方案数相加
printf("%I64d",ans);
return 0;
}
相关文章推荐
- 在N*N的棋盘上(1<=N<=10)请填入1,2,...N2共N2个数,使得任意两个相邻的数之和为素数。
- zoj 3316 Game 一般图最大匹配+博弈 有N个棋子在棋盘上,2个人轮流拿走一个棋子,第一步可以拿任意一个,而之后每一步必须拿上一步拿走的棋子曼哈顿长度L以内的棋子,问,后手是否能赢
- 数组A中任意两个相邻元素大小相差1,在其中查找某个数。
- 【面试题】-数组A中任意两个相邻元素大小相差1,找出某个数在数组A中的位置。(所有位置 )
- 用单循环链表存储一个环上的数据,并计算任意两个相邻元素之差是否超过2
- 将1,2,3,。。。,20这20个连续的自然数排成一圈,使任意两个相邻的自然数之和均为素数。
- (笔试题)数组A中任意两个相邻元素大小相差1,在其中查找某个数。
- [百度]数组A中任意两个相邻元素大小相差1,在其中查找某个数
- php 求一个无序数组经过排列后任意两个相邻元素之差的最大值(算法)
- 求一个二叉树中任意两个节点间的最大距离,两个节点的距离的定义是这两个节点间边的个数,比如某个孩子节点和父节点间的距离是1,和相邻兄弟节点间的距离是2,
- 数组A中任意两个相邻元素大小相差1,现给定这样的数组A和目标整数t,找出t在数组A中的位置。
- 将1-20这二十个连续的自然数排成一圈,使任意两个相邻的自然数之和均为素数
- 任意创建偶数个button,每两个button一行,通过点击任何按钮,可以实现相邻按钮间的颜色转换
- [经典面试题][百度]数组A中任意两个相邻元素大小相差1,在其中查找某个数。
- 数组A中任意两个相邻元素大小相差1
- 将[1,n^2]区间内n^2个数字分别填充到n*n的矩阵里,要求任意两个相邻的数字的和,它们的最大值最小是多少?
- C语言输入十个数,任意相邻的两个数不同,输出所有的递增,递减序列
- [百度]数组A中任意两个相邻元素大小相差1,在其中查找某个数。
- 微软面试题: 找出二叉树上任意两个结点的最近共同父结点。
- 两个栈实现一个队列,C语言实现,队列可伸缩,容纳任意数目的元素。