简单搜索(1-6, 9)

  1. poj1321 https://vjudge.net/problem/POJ-1321
    题意:在一个n*n棋盘的指定位置放K个棋子,同一行同一列只能放一个,问方案数。
    题解:标准dfs
    代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

int n, k;
int ans;
char mp[10][10];
int lie[10];


void dfs(int now, int num){
    if(num == k){
        ans++;
        return;
    }
    if(now == n)
        return;
    dfs(now+1, num);
    for(int i = 0; i < n; i++){
        if(mp[now][i] == '#' && lie[i] == 0){
            lie[i] = 1;
            dfs(now+1, num+1);
            lie[i] = 0;
        }
    }
}


int main(){
    while(scanf("%d%d",&n, &k)==2){
        if(n == -1 && k == -1)
            break;
        ans = 0;
        for(int i = 0; i < 10; i++){
            lie[i] = 0;
            for(int j = 0; j < 10; j++){
                mp[i][j] = '.';
            }
        }
        for(int i = 0; i < n; i++){
            scanf("%s", mp[i]);
        }
        dfs(0,0);
        printf("%d\n", ans);
    }
return 0;
}

2 .poj2251 https://vjudge.net/problem/POJ-2251
题意:三维的做迷宫问题
题解:bfs,比传统迷宫多了两个方向而已
代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;

int L, R, C;
char ma[35][35][35];

struct node{
    int l,r,c;
    int time;
}st, ed;


int dd[6][3] = { {1,0,0},{-1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1} };


void read(){
    for(int i = 0; i < L; i++){
        for(int j = 0; j < R; j++){
            scanf("%s", ma[i][j]);
            for(int k = 0; k < C; k++){
                if(ma[i][j][k] == 'S'){
                    st.l = i, st.r = j, st.c = k;
                }
                if(ma[i][j][k] == 'E'){
                    ed.l = i, ed.r = j, ed.c = k;
                }
            }
        }
        getchar();
    }
}


bool check(node x){
    if(x.l<0||x.r<0||x.c<0||x.l>=L||x.r>=R||x.c>=C||ma[x.l][x.r][x.c]=='#')
        return false;
    return true;
}

int bfs(node st, node ed){
    queue<node> Q;
    Q.push(st);
    while(!Q.empty()){
        st = Q.front();
        Q.pop();
        if(st.l == ed.l && st.r == ed.r && st.c == ed.c){
            return st.time;
        }
        for(int i = 0; i < 6; i++){
            node q = st;
            q.l += dd[i][0];
            q.r += dd[i][1];
            q.c += dd[i][2];
            q.time++;
            if(check(q)){
                ma[q.l][q.r][q.c] = '#';

                Q.push(q);
            }
        }
    }
    return -1;
}



int main(){
    while(scanf("%d %d %d", &L, &R, &C)){
        if(L==0 && R==0 && C==0)
            break;
        read();
        int ans = bfs(st, ed);
        if(ans == -1)
            printf("Trapped!\n");
        else{
            printf("Escaped in %d minute(s).\n", ans);
        }
    }
return 0;
}

3 .poj3278 https://vjudge.net/problem/POJ-3278
题意:农夫抓牛,农夫从x到x-1, x+1, 2*x坐标所用时间都是1min,问从初始坐标到牛最少时间。
题解:对每个点,把它和x-1, x+1, x*2连边,在图上跑最短路即可。(dij, spfa)
代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define LL long long 

const int maxn = 100005;
const int maxe = 300015;


int tot;
int head[maxn];
int dis[maxn];
int vis[maxn];

struct edge{
    int v, w, next;
}e[maxe];

void add(int x, int y, int w){
    e[++tot].v = y;
    e[tot].w = w;
    e[tot].next = head[x];
    head[x] = tot;
}

int spfa(int st, int ed){
    memset(dis, 0x3f, sizeof(dis));
    queue<int> Q;
    dis[st] = 0;
    vis[st] = 1;
    Q.push(st);
    while(!Q.empty()){
        int x = Q.front();
        Q.pop();
        vis[x] = 0;
        for(int i = head[x]; i != -1; i = e[i].next){
            int y = e[i].v;
            int w = e[i].w;
            if(dis[y] > dis[x] + w){
                dis[y] = dis[x] + w;
                if(!vis[y]){
                    Q.push(y);
                    vis[y] = 1;
                }
            }
        }
    }
    printf("%d\n", dis[ed]);
}


int main(){
    tot = -1;
    int n, k;
    scanf("%d%d", &n, &k);
    memset(head, -1, sizeof(head));
    add(0, 1, 1);
    for(int i = 1; i < maxn; i++){
        add(i, i+1, 1);
        add(i, i-1, 1);
        if(i < maxn/2-1)
            add(i, 2*i, 1);
    }
    spfa(n ,k);
}

4 .poj3279 https://vjudge.net/problem/POJ-3279
题意:开关问题, 每次翻牌会使周围4个一起翻,问全部变成0的最少翻转方案。
题解:二进制压缩枚举第一行的翻转方案,往下递推,最后检查最后一行是否全为0.
代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int inf = 0x3f3f3f3f;

int mp[20][20], st[20][20], v[20][20], res[20][20];
int ans = inf;
int dx[] = {0, -1, 1, 0, 0};
int dy[] = {1, 0, 0, -1, 0};

void flip(int x, int y){
    int xx, yy;
    for(int i = 0; i < 5; i++){
        xx = x + dx[i];
        yy = y + dy[i];
        st[xx][yy] = !st[xx][yy];
    }
}

int main(){
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            scanf("%d", &mp[i][j]);
        }
    }
    int all = 1 << m;
    for(int i = 0; i < all; i++){
        int tmp = 0;
        int flag = 0;
        for(int j = 1; j <= n; j++){
            for(int k = 1; k <= m; k++){
                st[j][k] = mp[j][k];
            }
        }
        for(int j = 0; j < 20; j++){
            for(int k = 0; k < 20; k++){
                v[j][k] = 0;
            }
        }
        for(int j = 0; j < m; j++){
            if( (i >> j) & 1 ){
                flip(1, j+1);
                v[1][j+1] = 1;
                tmp++;
            }
        }
        for(int j = 2; j <= n; j++){
            for(int k = 1; k <= m; k++){
                if(st[j-1][k]){
                    flip(j, k);
                    v[j][k] = 1;
                    tmp++;
                }
            }
        }
        for(int j = 1; j <= m; j++){
            if(st[n][j]){
                flag = 1;
                break;
            }
        }
        if(!flag && tmp < ans){
            ans = tmp;
            for(int j = 1; j <= n; j++){
                for(int k = 1; k <= m; k++){
                    res[j][k] = v[j][k];
                }
            }
        }
    }
    if(ans == inf){
        printf("IMPOSSIBLE\n");
        return 0;
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            printf("%d ", res[i][j]);
        }
        printf("\n");
    }
return 0;
}

5 .poj1426 https://vjudge.net/problem/POJ-1426
题意:对于一个数n(1 <= n <=200)找出一个只由0,1构成的十进制数,是它的倍数。(0倍不算)
题解:bfs,首位必然为1, 相当于依次填数,并检查是否为n的倍数。
吐槽:我的代码这么暴力竟然过了。。。
代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>


using namespace std;

void bfs(int n){
    queue<long long> q;
    q.push(1);
    while(q.size()){
        long long x = q.front();
        q.pop();
        if(x % n == 0){
            printf("%lld\n", x);
            return;
        }
        q.push(x*10);
        q.push(x*10+1);
    }
}


int main(){
    int n;
    while(scanf("%d", &n) && n){
        bfs(n);
    }
return 0;
}

6 .poj 3126 https://vjudge.net/problem/POJ-3126
题意:要求从一个素数(4位)变化为另一个素数(4位),每次变一个数字,中间过程也必须是素数,求最小变化次数?
题解:bfs,每次把能变成的素数入队,和最短路相似的方法res[x] = res[y] + 1更新答案。
代码:

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>

using namespace std;

int T, n, m;
int ans;

int vis[10005];
int res[10005];
int prime[10005];
int v[10005];
int tt;

void Prime(){
    memset(v, 0, sizeof(v));
    tt = 0;
    for(int i = 2; i <= 10000; i++){
        if(!v[i]){
            v[i] = i;
            prime[++tt] = i;
        }
        for(int j = 1; j <= tt; j++){
            if(v[i] < prime[j] || prime[j] > 10000 / i)
                break;
            v[i*prime[j]] = prime[j];
        }
    }
}

int bfs(){
    memset(vis, 0, sizeof(vis));
    memset(res, 0, sizeof(res));
    queue<int> q;
    int x, ttt, k;
    int now[5];
    q.push(n);
    vis[n] = 1;
    while(q.size()){
        x = q.front();
        q.pop();
        now[4] = x % 10;
        now[3] = (x / 10)%10;
        now[2] = (x / 100) % 10;
        now[1] = x/1000;
        for(int i = 1; i <= 4; i++){
            k = 0;
            ttt = now[i];
            if(i == 1)
                k = 1;
            for(int j = k; j <= 9; j++){
                if(j == ttt)
                    continue;
                now[i] = j;
                int sum = now[1]*1000 + now[2]*100 + now[3]*10 + now[4];
                if(v[sum] == sum && !vis[sum]){
                    q.push(sum);
                    vis[sum] = 1;
                    res[sum] = res[x] + 1;
                }
                if(sum == m)
                    return res[sum];
            }
            now[i] = ttt;
        }
        if(x == m)
            return res[x];
    }
    return -1;
}

int main(){
    Prime();
    scanf("%d", &T);
    while(T--){
        scanf("%d %d", &n, &m);
        ans = bfs();
        if(ans == -1)
            printf("Impossible\n");
        else
            printf("%d\n", ans);
    }
return 0;
} 

9 .fzu2150 https://vjudge.net/problem/FZU-2150
题意:大概就是在平面上任意选两个有草的位置点火,一分钟向周围扩散一圈,问把草烧光的最短时间。(记不清了,大概这意思)
题解:枚举这两个位置,bfs算出时间,取最小值即可
代码(略丑)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;

int T ,n, m;
char mp[20][20];
int v[20][20];
int ans;
int tot, cnt;
int d[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
struct node{
    int x, y;
    int time;
};

queue<node> q;

int bfs(){
    int res = 0x3f3f3f3f;
    while(!q.empty()){
        node now = q.front();
        q.pop();
        cnt++;
        if(cnt == tot){
            res = now.time;
            break;
        }
        for(int i = 0; i < 4; i++){
            node ss = now;
            ss.x += d[i][0];
            ss.y += d[i][1];
            ss.time++;
            if(ss.x>=0&&ss.y>=0&&ss.x<n&&ss.y<m&&!v[ss.x][ss.y]&&mp[ss.x][ss.y]=='#'){
                v[ss.x][ss.y] = 1;
                q.push(ss);
            }   
        }
    }
    while(!q.empty()) q.pop();
    return res;
}


int main(){
    int kase = 0;
    scanf("%d", &T);
    while(T--){
        while(!q.empty()) q.pop();
        tot = cnt = 0;
        ans = 0x3f3f3f3f;
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; i++){
            scanf("%s", mp[i]);
            for(int j = 0; j < m; j++){
                if(mp[i][j] == '#')
                    tot++;
            }
        }
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                for(int r = 0; r < n; r++){
                    for(int c = 0; c < m; c++){
                        if(mp[i][j] == '#' && mp[r][c] == '#'){
                            cnt = 0;
                            memset(v, 0, sizeof(v));
                            node st1;
                            st1.x = i, st1.y = j, st1.time = 0;
                            v[i][j] = 1;
                            q.push(st1);
                            if(i != r || j != c){
                                node st2;
                                st2.x = r, st2.y = c, st2.time = 0;
                                q.push(st2);
                                v[r][c] = 1;
                            }
                            ans = min(ans, bfs());  
                        }
                    }
                }
            }
        }
        printf("Case %d: ", ++kase);
        if(ans == 0x3f3f3f3f)
            printf("-1\n");
        else
            printf("%d\n", ans);
    }   
return 0;
}

猜你喜欢

转载自blog.csdn.net/yczhaoxun/article/details/81625517
1-6
9-6
9-1