A - 棋盘问题
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
Input
输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
Output
对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。
Sample Input
2 1
#.
.#
4 4
...#
..#.
.#..
#...
-1 -1
Sample Output
2
1
一道DFS题,给一个n级矩阵,k个棋子,限制条件为每行每列只能放一个棋子。因此我们可以每行每行的搜索,看成一个n层树,找到一个可行结点后搜索下一层,若找不到返回上一层继续搜索。代码+注释如下。
#include<bits/stdc++.h>
using namespace std;
char mp[10][10];//绘制地图
int vis[10];//因为从每行搜,所以只需标记每列是否被访问
int r,c,n,k,sum;//行,列,矩阵大小,棋子个数,方案总和
void dfs(int r,int w){ //r表示搜索当前行,w表示为当前放棋子个数
if(w>=k)//终止条件,如果放完所有棋子,方案数+1
{
sum++;//!!!!!此处if(里面两个语句应该大括号,没输大括号导致WA
return;
}
for(int i=r;i<n;i++)
for(int j=0;j<n;j++)
{
if(!vis[j]&&mp[i][j]=='#')
{
vis[j]=1;//放置该棋子后该列标记
dfs(i+1,w+1);//!!!!此处应该是搜索i+1行,而不是r+1
vis[j]=0;//清楚标记,防止下次访问再放置该列
}
}
return;
}
int main(){
while(cin>>n>>k)
{
if(n==-1&&k==-1) break;
memset(vis,0,sizeof(vis));//每次输入一组数据就将其初始化
memset(mp,0,sizeof(mp));
for(int i=0;i<n;i++)
cin>>mp[i];
sum=0;
dfs(0,0);
cout<<sum<<endl;
}
return 0;
}
B-石油采集
随着海上运输石油泄漏的问题,一个新的有利可图的行业正在诞生,那就是撇油行业。如今,在墨西哥湾漂浮的大量石油,吸引了许多商人的目光。这些商人们有一种特殊的飞机,可以一瓢略过整个海面20米乘10米这么大的长方形。(上下相邻或者左右相邻的格子,不能斜着来)当然,这要求一瓢撇过去的全部是油,如果一瓢里面有油有水的话,那就毫无意义了,资源完全无法利用。现在,商人想要知道,在这片区域中,他可以最多得到多少瓢油。
地图是一个N×N的网络,每个格子表示10m×10m的正方形区域,每个区域都被标示上了是油还是水
Input
测试输入包含多条测试数据
测试数据的第一行给出了测试数据的数目T(T<75)
每个测试样例都用数字N(N<50)来表示地图区域的大小,接下来N行,每行都有N个字符,其中符号’.’表示海面、符号’#’表示油面。
Output
输出格式如下“Case X: M”(X从1开始),M是商人可以最多得到的油量。
示例1
输入
1
6
......
.##...
......
.#..#.
.#..##
......
输出
Case 1: 3
一个DFS+数学题,一个n级矩阵,找到最大油量,建立x-y坐标系,易知上下左右相邻两点坐标之和必为一奇一偶,即一个油量必须包含两个坐标和为一奇一偶的点,由下图知,取奇数和偶数的最小值即为油量数
代码如下
#include<bits/stdc++.h>
using namespace std;
char s[60][60];
int odd,even,n;
void dfs(int x,int y){
if (x>=n||y>=n||x<0||y<0||s[x][y]=='.') return;//越界或者无油则返回
(x+y)&1?++odd:++even;//如果x+y和为奇数则odd++,偶数even++;
s[x][y]='.';//标记
dfs(x+1,y);//四个方向搜索
dfs(x-1,y);
dfs(x,y+1);
dfs(x,y-1);
}
int main(){
int t,kase=0;
cin>>t;
while(t--){
scanf("%d",&n);
int ans=0;
for (int i=0; i<n; ++i) cin>>s[i];//绘图
for (int i=0; i<n; ++i)
for (int j=0; j<n; ++j)
if (s[i][j]=='#'){
odd=even=0;//每次都要初始化
dfs(i,j);
ans+=min(odd,even);
}
printf("Case %d: %d\n",++kase,ans);
}
}