Problem A:棋盘问题
题目大意:给N*N大小棋盘,M个棋子,问要将棋子放在棋盘中的’#’位置有几种方法..
思路:按行回溯搜索..
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n, k, sum;
char m[10][10];
bool col[10]; //记录行状态
void dfs(int cur, int cnt) {
if(cnt == 0) {
sum++; //若棋子恰好放置完全,则方法数加一
}
for(int i = cur + 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(m[i][j] == '#' && col[j] == false) {
col[j] = true; //该行已放置棋子
dfs(i, cnt - 1); //放置后进入i层搜索
col[j] = false; //用于回溯
}
}
}
}
int main() {
while(scanf("%d %d", &n, &k) != EOF) {
sum = 0;
if(n == -1 && k == -1) {
break;
}
for(int i = 1; i <= n; i++) {
scanf("%s", m[i] + 1);
}
memset(col, false, sizeof col);
dfs(0, k); //从0行开始搜索
printf("%d\n", sum);
}
return 0;
}
Problem B:Find The Multiple
题目大意 :找出某个数的倍数且该倍数只由0和1组成..
思路:计算发现,答案其实可以用ull存放,枚举0和1,DFS..
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
int n;
unsigned long long ans; //测试数据过大,需使用ull存储
bool flag;
void dfs(unsigned long long cur, int deep) { //deep为我们搜索数字的长度
if(cur % n == 0) { //若找到可以进行整除操作的数,则退出
flag = true;
ans = cur;
return ;
}
if(deep == 19) return ; //由样例输出得知,答案最长18位,若越界则退出
if(!flag) dfs(cur * 10, deep + 1); //下一位枚举0
if(!flag) dfs(cur * 10 + 1, deep + 1); //下一位枚举1
}
int main() {
while(scanf("%llu", &n), n) {
flag = false;
dfs(1, 0); //从1开始搜索
printf("%llu\n", ans);
}
return 0;
}
附上打表代码:
#include <stdio.h>
int main()
{
char a[200][30] = {{"1"},{"10"},{"111"},{"100"},{"10"},{"1110"},{"1001"},{"1000"},{"111111111"},{"10"},{"11"},{"11100"},{"1001"},{"10010"},{"1110"},{"10000"},{"11101"},{"1111111110"},{"11001"},{"100"},{"10101"},{"110"},{"110101"},{"111000"},{"100"},{"10010"},{"1101111111"},{"100100"},{"1101101"},{"1110"},{"111011"},{"100000"},{"111111"},{"111010"},{"10010"},{"11111111100"},{"111"},{"110010"},{"10101"},{"1000"},{"11111"},{"101010"},{"1101101"},{"1100"},{"1111111110"},{"1101010"},{"10011"},{"1110000"},{"1100001"},{"100"},{"100011"},{"100100"},{"100011"},{"11011111110"},{"110"},{"1001000"},{"11001"},{"11011010"},{"11011111"},{"11100"},{"100101"},{"1110110"},{"1111011111"},{"1000000"},{"10010"},{"1111110"},{"1101011"},{"1110100"},{"10000101"},{"10010"},{"10011"},{"111111111000"},{"10001"},{"1110"},{"11100"},{"1100100"},{"1001"},{"101010"},{"10010011"},{"10000"},{"1111111101"},{"111110"},{"101011"},{"1010100"},{"111010"},{"11011010"},{"11010111"},{"11000"},{"11010101"},{"1111111110"},{"1001"},{"11010100"},{"10000011"},{"100110"},{"110010"},{"11100000"},{"11100001"},{"11000010"},{"111111111111111111"},{"100"},{"101"},{"1000110"},{"11100001"},{"1001000"},{"101010"},{"1000110"},{"100010011"},{"110111111100"},{"1001010111"},{"110"},{"111"},{"10010000"},{"1011011"},{"110010"},{"1101010"},{"110110100"},{"10101111111"},{"110111110"},{"100111011"},{"111000"},{"11011"},{"1001010"},{"10001100111"},{"11101100"},{"1000"},{"11110111110"},{"11010011"},{"10000000"},{"100100001"},{"10010"},{"101001"},{"11111100"},{"11101111"},{"11010110"},{"11011111110"},{"11101000"},{"10001"},{"100001010"},{"110110101"},{"100100"},{"10011"},{"100110"},{"1001"},{"1111111110000"},{"11011010"},{"100010"},{"1100001"},{"11100"},{"110111"},{"11100"},{"1110001"},{"11001000"},{"10111110111"},{"10010"},{"1110110"},{"1010100"},{"10101101011"},{"100100110"},{"100011"},{"100000"},{"11101111"},{"11111111010"},{"1010111"},{"1111100"},{"1111110"},{"1010110"},{"11111011"},{"10101000"},{"10111101"},{"111010"},{"1111011111"},{"110110100"},{"1011001101"},{"110101110"},{"100100"},{"110000"},{"100101111"},{"110101010"},{"11010111"},{"11111111100"},{"1001111"},{"10010"},{"100101"},{"110101000"},{"1110"},{"100000110"},{"1001011"},{"1001100"},{"1010111010111"},{"110010"},{"11101111"},{"111000000"},{"11001"},{"111000010"},{"101010"},{"110000100"},{"1101000101"},{"1111111111111111110"},{"111000011"},{"1000"}};
int n;
while(scanf("%d",&n)!=EOF)
{
if(n == 0)
break;
printf("%s\n", a[n - 1]);
}
return 0;
}
Problem C: Oil Deposits 题目大意 :找有几块油田,连在一起的算一块..
思路 :八个方向搜,DFS.
#include<stdio.h>
#include<string.h>
char a[111][111];
int s,m,n;
void dfs(int x,int y)
{
if(a[x][y]=='*'||x<0||y<0||x>m-1||y>n-1)
return;//如果不是油田或者超出就返回
else
{
a[x][y] = '*';//找到就标记掉
dfs(x-1,y-1);
dfs(x-1,y);
dfs(x-1,y+1);
dfs(x,y-1);
dfs(x,y+1);
dfs(x+1,y-1);
dfs(x+1,y);
dfs(x+1,y+1);//八个方向搜
}
}
int main()
{
int i,j;
while(scanf("%d %d",&m,&n)!=EOF,m||n)
{
for(i=0;i<m;i++)
{
scanf("%s",a[i]);
}
s=0;//记录有几块
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
if(a[i][j]=='@')//找到一块,开始扩展
{
dfs(i,j);
s++;//找完一次,总数加一
}
}
}
printf("%d\n",s);
}
return 0;
}
Problem D:Red and Black
题目大意 :@为起点,可以上下左右四个方向扩展,只能走'.',问能走过多少个点..思路 :上一题的八个方向改为四个,DFS..
#include<stdio.h>
#include<string.h>
char a[111][111];
int s,m,n;
void dfs(int x,int y)
{
if(a[x][y]=='#'||x<0||y<0||x>n-1||y>m-1)
return;//如果不是点或者超出就返回
else
{
a[x][y] = '#';//找到就标记掉(起点第一次就标记掉,总数加一)
s++;//标记完点数量加一
dfs(x-1,y);
dfs(x,y-1);
dfs(x,y+1);
dfs(x+1,y); //四个方向搜
}
}
int main()
{
int i,j,x,y;
while(scanf("%d %d",&m,&n)!=EOF,m||n)
{
for(i=0;i<n;i++)
{
scanf("%s",a[i]);
}
s=0;//记录点数量
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
if(a[i][j]=='@')
{
x=i;
y=j; //找到起点,记录坐标
}
}
}
dfs(x,y);//从坐标开始搜
printf("%d\n",s);
}
return 0;
}
Problem E:Tempter of the Bone
题目大意 :S为起点,D为终点,问能否恰好在t时刻到达终点..思路 :DFS+奇偶剪枝,普通深搜会超时,要剪枝..
TLE之后改了好久,才知道要剪枝.不剪枝过不掉啊..
奇偶剪枝:
若 t-[abs(ex-sx)+abs(ey-sy)] 结果为非偶数(奇数),则无法在t步恰好到达;
返回,false;
反之亦反..
#include<stdio.h>
#include<string.h>
#include<math.h>
int a[10][10];
char ma[10][10];
int i,j,n,m,t,x,y,flag,ex,ey,s;
void dfs(int x,int y)
{
if(flag==1)//能走到,返回
return;
if(s>t)//超过了还没到,返回
return;
if(x==ex&&y==ey&&s==t)//到达终点坐标,且在t时到,标记能,返回
{
flag=1;
return;
}
if((x-1)>=0&&(x-1)<n&&y>=0&&y<m&&a[x-1][y]==0&&ma[x-1][y]!='X')//向上
{
a[x-1][y]=1;
s++;
dfs(x-1,y);
a[x-1][y]=0;//不能要重置回去
s--;
}
if((x+1)>=0&&(x+1)<n&&y>=0&&y<m&&a[x+1][y]==0&&ma[x+1][y]!='X')//向下
{
a[x+1][y]=1;
s++;
dfs(x+1,y);
a[x+1][y]=0;
s--;
}
if(x>=0&&x<n&&(y-1)>=0&&(y-1)<m&&a[x][y-1]==0&&ma[x][y-1]!='X')//向左
{
a[x][y-1]=1;
s++;
dfs(x,y-1);
a[x][y-1]=0;
s--;
}
if(x>=0&&x<n&&(y+1)>=0&&(y+1)<m&&a[x][y+1]==0&&ma[x][y+1]!='X')//向右
{
a[x][y+1]=1;
s++;
dfs(x,y+1);
a[x][y+1]=0;
s--;
}
}
int main()
{
while(scanf("%d %d %d",&n,&m,&t)!=EOF,m||n||t)
{
getchar();
for(i=0;i<n;i++)
{
scanf("%s",ma[i]);
for(j=0;j<m;j++)
{
if(ma[i][j]=='S')
{
x=i;
y=j;//记录起点坐标
}
if(ma[i][j]=='D')
{
ex=i;
ey=j;//记录终点坐标
}
}
}
memset(a,0,sizeof(a));
a[x][y]=1;
flag=0;//标记是否能到达
s=0;
if((abs(x-ex)+abs(y-ey)-t)%2!=0)//奇偶剪枝, 关键 !!!
{
printf("NO\n");
}
else
{
dfs(x,y);
if(flag)
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}
Problem F:Prime Ring Problem
题目大意 :将1~n个数无序连成环,使得该环相邻两个数之和为素数。
思路 :环的第一个数总为1,我们只需枚举当前位置的下一个数字,使得该数字与当前位置数字之和为素数,即可进入下个位置的搜索,到达位置n时,若位置n上的数与第一个位置上的数字(其实就是1)的和若也为素数,则我们搜索到了合法解,输出即可..
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int a[25]; //用于存储答案
bool b[25]; //记录数字使用状态
int n;
//素数判断,千万别写错。。。
bool prime(int m) {
for(int i = 2; i * i <= m; i++) {
if(m % i == 0) {
return false;
}
}
return true;
}
void dfs(int deep) {
if(deep == n) { //若深度已到达n,即可进行合法性判断
if(prime(1 + a[n])) { //判断最后一个数和第一个数的和是否为素数
for(int i = 1; i <= n; i++) { //若符合,则输出答案
printf(i == 1 ? "%d" : " %d", a[i]);
}
printf("\n");
}
return;
}
for(int i = 2; i <= n; i++) {
//若枚举的数字未被使用,且与当前deep深度位置数字之和为素数
if(b[i] == false && prime(a[deep] + i)) {
b[i] = true; //表示这个数字已被使用
a[deep + 1] = i; //将这个数添加进答案数组
dfs(deep + 1); //深度+1,继续搜索
b[i] = false; //用于回溯,其他可
}
}
}
int main() {
int cnt = 0;
while(scanf("%d", &n) != EOF) {
memset(a, 0, sizeof a);
memset(b, false, sizeof b);
a[1] = 1;
b[1] = true; //1总是第一位数字,已被使用
printf("Case %d:\n", ++cnt);
dfs(1); //第一位数字即为第1层深度
printf("\n");
}
return 0;
}