搜索(DFS/BFS)
棋盘问题
poj - 1321
#include<cstdio>
using namespace std;
int n, k;
int ans = 0;
int pic[10][10];
int cc[10];
void dfs(int r, int c, int num, int flag){//flag 标记是否选择
if(num == k){
if(flag)
cc[c] = 0; //回溯
ans ++;
return;
}
if(r == n-1){
if(flag)
cc[c] = 0; //回溯
return;
}
dfs(r+1, 0, num, 0);//这行不选
for(int j = 0; j < n; ++ j){//选
if(pic[r+1][j] == '#' && cc[j] == 0){
cc[j] = 1;
dfs(r+1, j, num+1, 1);
}
}
if(flag)
cc[c] = 0;//回溯
}
int main(){
while(scanf("%d %d", &n, &k)){
getchar();
if(n == -1 && k == -1)
break;
for(int i = 0; i < n; ++ i){
for(int j = 0; j < n; ++ j)
scanf("%c", &pic[i][j]);
getchar();
}
ans = 0;
for(int q = 0; q < n; ++ q){
cc[q] = 0;
}
dfs(0, 0, 0, 0);//这行不选
for(int j = 0; j < n; ++ j){//这行选
for(int q = 0; q < n; ++ q){
cc[q] = 0;
}
if(pic[0][j] == '#' && cc[j] == 0){
cc[j] = 1;
dfs(0, j, 1, 1);
}
}
printf("%d\n", ans);
}
}
poj 1753
//最多 16个点 都选择, 每个点最多选一次,选两次就如同没选
//样例的答案 : 4选择的四个点
//0 0
//1 1
//1 3
//2 0
#include<cstdio>
using namespace std;
const int INF = 0x3f3f3f3f;
int ans;
char ch;
int pic[5][5];
int vis[5][5];
int addx[5] = {0, 1, -1, 0, 0};//自己与周围要发生改变
int addy[5] = {0, 0, 0, 1, -1};
int use[17][3];//用来存选择的点
bool check1(){//判断是否棋盘上棋子都相同
for(int i = 0; i < 4; ++ i)
for(int j = 0; j < 4; ++ j)
if(pic[i][j] != pic[0][0])
return false;
return true;
}
bool check2(int x, int y){//判断边界
if(x >= 0 && x < 4 && y >= 0 && y < 4) return true;
return false;
}
void change(int x, int y){//改变棋子类型
for(int i = 0; i < 5; ++ i){
int xx = x + addx[i];
int yy = y + addy[i];
if(check2(xx, yy)){
pic[xx][yy] = !pic[xx][yy];
}
}
}
void dfs(int x, int y, int t, int flag){//t 表示步数,flag 表示该点是否有选择
vis[x][y] = 1;//已做过选择,接下来不会再选
if(t == ans){// 接下来的选择一定不满足
vis[x][y] = 0;
return;
}
if(flag)//选择了就要改变
change(x, y);
// if(flag)
// use[t][0] = x, use[t][1] = y;
if(check1()){
//printf("ans\n\n\n");
//printf("%d %d %d %d\n", x, y, t, flag);
//for(int i = 1; i < 17; ++ i)
// printf("%d %d\n ", use[i][0], use[i][1]);
//printf("\n");
vis[x][y] = 0;//回溯
if(flag)
change(x, y);//回溯
// if(flag)
// use[t][0] = 0, use[t][1] = 0;
if(t < ans)
ans = t;
return;
}
int flagg = 1;
for(int i = 0; i < 4; ++ i){
for(int j = 0; j < 4; ++ j){
if(vis[i][j] == 0){//找到下一个点
dfs(i, j, t, 0);//不选
dfs(i, j, t+1, 1);//选
flagg = 0;
break;
}
}
if(flagg == 0)
break;
}
if(flag)
change(x, y);//回溯
// if(flag)
// use[t][0] = 0, use[t][1] = 0;
vis[x][y] = 0;//回溯
}
int main(){
for(int i = 0; i < 4; ++ i){
for(int j = 0; j < 4; ++ j){
scanf("%c", &ch);
if(ch == 'w')
pic[i][j] = 1;
else
pic[i][j] = 0;
}
getchar();
}
ans = INF;
dfs(0, 0, 0, 0);//不选
dfs(0, 0, 1, 1);//选
if(ans == INF)
printf("Impossible\n");
else
printf("%d\n", ans);
}
更好
#include <stdio.h>
const int inf=9999999;
char s[10];
int map[10][10],i,j;
int ans=inf;
int panduan(){
int x=map[0][0];
for (i=0; i<4; i++){
for (j=0; j<4; j++){
if (map[i][j]!=x)
return 0;
}
}
return 1;
}
void fan (int x,int y){
map[x][y]=!map[x][y];
if (x - 1 >= 0)
map[x-1][y]=!map[x-1][y];
if (x + 1 < 4)
map[x+1][y]=!map[x+1][y];
if (y - 1 >= 0)
map[x][y-1]=!map[x][y-1];
if (y + 1 < 4)
map[x][y+1]=!map[x][y+1];
}
int dfs (int x,int y,int t){
if ( panduan()){
if (ans > t)
ans = t ;
return 0;
}
if (x >= 4 || y >= 4)
return 0;
int nx,ny;
nx = (x + 1)%4;
ny = y + ( x + 1 ) / 4;
dfs (nx,ny,t);
fan (x,y);
dfs (nx,ny,t+1);
fan (x,y);
return 0;
}
int main (){
for (i=0; i<4; i++){
scanf ("%s",s);
for (j=0; j<4; j++){
if (s[j]=='b')
map[i][j]=0;
else
map[i][j]=1;
}
}
dfs (0,0,0);
if (ans == inf )
printf ("Impossible\n");
else printf ("%d\n",ans);
return 0;
}
连通块问题
HDU - 2102
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
char pic[2][12][12];
int vis[2][12][12];
int T;
int n, m, t;
int eh, er, ec;
int flag;
typedef struct node{
int h, r, c, t;
}node;
int addr[4] = {1, -1, 0, 0};
int addc[4] = {0, 0, 1, -1};
bool check(int h, int r, int c){
if(r >= n || r < 0 || c >= m || c < 0 || vis[h][r][c] || pic[h][r][c] == '*') return true;
return false;
}
void bfs(int h, int r, int c){
node temp;
temp.h = h, temp.r = r, temp.c = c, temp.t = 0;
vis[0][0][0] = 1;
queue<node> que;
que.push(temp);
while(!que.empty()){
node tt = que.front();
que.pop();
if(tt.h == eh && tt.r == er && tt.c == ec){
flag = 1;
break;
}
if(tt.t >= t)//接下来的点一定不满足条件,跳过
continue;
for(int i = 0; i < 4; ++ i){
temp = tt;
temp.r += addr[i];
temp.c += addc[i];
temp.t += 1;
if(check(temp.h, temp.r, temp.c))
continue;
vis[temp.h][temp.r][temp.c] = 1;
if(pic[temp.h][temp.r][temp.c] == '#'){//'#'号的地方自动跳到不同楼层的相同位置
temp.h = !temp.h;
if(check(temp.h, temp.r, temp.c) || pic[temp.h][temp.r][temp.c] == '#')
continue;
vis[temp.h][temp.r][temp.c] = 1;
}
if(temp.h == eh && temp.r == er && temp.c == ec){
flag = 1;
break;
}
que.push(temp);
}
}
}
int main(){
scanf("%d\n", &T);
while(T--){
scanf("%d %d %d\n", &n, &m, &t);
for(int i = 0; i < 2; ++ i){
for(int j = 0; j < n; ++ j){
for(int k = 0; k < m; ++ k){
scanf("%c", &pic[i][j][k]);
vis[i][j][k] = 0;
if(pic[i][j][k] == 'P')
eh = i, er = j, ec = k;
}
getchar();
}
if(i == 0)
getchar();
}
flag = 0;
bfs(0, 0, 0);
if(flag)
printf("YES\n");
else
printf("NO\n");
}
}
FZU - 2150
连通块,染色问题
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
int t, n, m;
char pic[12][12];
int vis[12][12];
int len[12][12];
int addx[4] = {1, -1, 0, 0};
int addy[4] = {0, 0, 1, -1};
typedef struct node{
int num, x, y, t;
}node;
node d[105];
int cnt = 0;
void init(){
for(int i = 0; i < n; ++ i)
for(int j = 0; j < m; ++ j)
vis[i][j] = 0;
}
bool check(int x, int y){
if(x >= 0 && x < n && y >= 0 && y < m && pic[x][y] == '#') return true;
return false;
}
void bfs(int x, int y){
init();
queue<node> que;
node pp;
pp.x = x, pp.y = y, pp.t = 0;
vis[x][y] = 1;
len[x][y] = 0;
que.push(pp);
while(!que.empty()){
node p = que.front();
que.pop();
for(int i = 0; i < 4; ++ i){
pp = p;
pp.x += addx[i];
pp.y += addy[i];
pp.t ++;
if(check(pp.x, pp.y) && vis[pp.x][pp.y] == 0){
len[pp.x][pp.y] = min(len[pp.x][pp.y], pp.t);
vis[pp.x][pp.y] = 1;
que.push(pp);
}
}
}
}
int main(){
int cc = 1;
for(scanf("%d\n", &t); t; t--){
scanf("%d %d\n", &n, &m);
cnt = 0;
for(int i = 0; i < n; ++ i){
for(int j = 0; j < m; ++ j){
scanf("%c", &pic[i][j]);
if(pic[i][j] == '#')//用结构体存可以当起点的点,题目保证至少有一个
d[cnt].num = cnt, d[cnt].x = i, d[cnt ++].y = j;
}
getchar();
}
int maxx = INF;
for(int i = 0; i < cnt; ++ i){
for(int j = i; j < cnt; ++ j){//暴力历遍所有选择两个点的可能
for(int k = 0; k < n; ++ k){
for(int z = 0; z < m; ++ z)
len[k][z] = INF;
}
bfs(d[i].x, d[i].y);
bfs(d[j].x, d[j].y);
int maxt = 0;
for(int k = 0; k < cnt; ++ k){
if(len[d[k].x][d[k].y] > maxt)
maxt = len[d[k].x][d[k].y];//找出这次选择的最大花费时间
}
maxx = min(maxt, maxx);//每次选择的最大花费时间中的最短时间
}
}
printf("Case %d: ", cc++);
if(maxx == INF)
printf("-1\n");
else
printf("%d\n", maxx);
}
}
其他问题
poj - 1426
#include<cstdio>
#include<queue>
using namespace std;
typedef long long ll;//题目中说不超过100位, 但是实际上,200以内的数longlong 就够了,
//不知道为什么
int flag;
void bfs(ll x){
queue<ll> que;
que.push(1);
while(!que.empty()){
ll k = que.front();
que.pop();
if(k % x == 0){
printf("%lld\n", k);
break;
}
que.push(k*10);
que.push(k*10+1);
}
}
int n;
int main(){
while(~scanf("%d", &n), n){
flag = 0;
bfs(n);
}
}
正规做法//用字符串爆空间
#include<iostream>
using namespace std;
int mod[524286]; //保存每次mod n的余数
//由于198的余数序列是最长的
//经过反复二分验证,436905是能存储198余数序列的最少空间
//但POJ肯定又越界测试了...524286是AC的最低下限,不然铁定RE
int main(int i)
{
int n;
while(cin>>n)
{
if(!n)
break;
mod[1]=1%n; //初始化,n倍数的最高位必是1
for(i=2;mod[i-1]!=0;i++) //利用同余模定理,从前一步的余数mod[i/2]得到下一步的余数mod[i]
mod[i]=(mod[i/2]*10+i%2)%n;
//mod[i/2]*10+i%2模拟了BFS的双入口搜索
//当i为偶数时,+0,即取当前位数字为0 。为奇数时,则+1,即取当前位数字为1
//模拟了01二叉数
i--;
int pm=0;
while(i)
{
mod[pm++]=i%2; //把*10操作转化为%2操作,逆向求倍数的每一位数字
i/=2;
}
while(pm)
cout<<mod[--pm]; //倒序输出
cout<<endl;
}
return 0;
}