时间限制: 1 Sec
内存限制: 128 MB
提交: 33
解决: 11
[提交][状态][讨论版]
题目描述
给出一个n * n的海洋,#代表海域,.代表冰山,要在海域中放置k个战舰,战舰会攻击同一行同一列的其他战舰,所以同一行同一列不能放置其他战舰,问摆放战舰的方案数目C有多少种(数据保证C<2^31)。
输入
输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,(n <= 8, k <= n)
随后的n行描述了的海洋的形状:每行有n个字符,其中 # 表示海域, . 表示冰山
输出
对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。
样例输入
2 1
#.
.#
4 4
…#
..#.
.#..
#…
样例输出
2
1
题意识先输入n表示n*n的海域,然后输入k表示需要放置k艘战舰,(k<=n),‘#’表示海域可以放战舰,‘.’表示不可以,且同一行同一列不能同时放置战舰,求可以有多少种放置方式
这道题与n皇后相似,都是说同一行同一列不能放置,但此题又比n皇后限制条件多一点,首先能放置的位置是固定的,某些点一定不能放,其次该题不似n皇后那样必须要放置n个,而是输入的k个,但大体上差不多
对于要求多少种方式的问题,若数据较小,便用dfs解决。
#include<cstdio>
#include<cstring>
int n,k,sum,flag;
char map[10][10];//记录地图
int w[10];//标记是否访问过
int can(int a,int b)
{
if(!w[b]&&map[a][b]=='#'&&a>=0&&a<n)
return 1;//return 1 的情况不能分开写
return 0;//在if的情况下return 0就会出错
}
void dfs(int a)//a表示第a行
{
if(flag>=k)//不要在这里用个大括号写使flag=0
sum++;//方式
else if(a==n)//绝对不能少!!
return ;
else
{
for(int i=0;i<n;i++)//i表示第a行的第i个
{
if(can(a,i))
{
w[i]=1;
flag++;//记录已经放置好了多少艘战舰
dfs(a+1);//访问下一行
w[i]=0;//还原
flag--;//不要忘 ,很重要
}
}
dfs(a+1);//若第a行没有放或者不能放,就要从a+1行访问
}
}
int main()
{
while(~scanf("%d%d",&n,&k))
{
int i;
sum=0;
flag=0;
memset(w,0,sizeof(w));
for(i=0;i<n;i++)
scanf("%s",&map[i]);
dfs(0);//从第0行开始访问
printf("%d\n",sum);
}
return 0;
}
#include<cstdio>
#include<cstring>
int n,k,sum;
char map[10][10];
int w[10];
int can(int a,int b)
{
if(a<0||a>=n||b<0||b>=n)//越界
return 0;
if(w[b]||map[a][b]=='.')//访问过或者不能放置
return 0;
return 1;
}
void dfs(int a,int b)//表示放置到了第a行,已经放置了b个
{
if(b==k)//放置完k个表示已经达到目标,方式sum++
sum++;
else if(a==n)//地图已经访问完了,结束
return ;
else
{
for(int i=0;i<n;i++)
{
if(!w[i]&&map[a][i]=='#')//为什么一定要写成立的情况,写不成立的情况就会WA
//第a行没有标记过并且第i列也没有被标记
{
w[i]=1;
dfs(a+1,b+1);
w[i]=0;
}
}
dfs(a+1,b);
}
}
int main()
{
while(~scanf("%d%d",&n,&k))
{
sum=0;
memset(w,0,sizeof(w));//w[i]表示第i列是否被标记过
for(int i=0;i<n;i++)
scanf("%s",&map[i]);
dfs(0,0);
printf("%d\n",sum);
}
return 0;
}