简单搜索(1-9, 11-13)

  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;
} 

7 .poj3087 https://vjudge.net/problem/POJ-3087
题意:按题目要求洗牌,问能不能洗成指定模样,能则输出步数,不能输出-1。
题解:就是模拟题,用map记录一下出现过没
代码:

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

int T, c;
char s1[205], s2[205], s12[205];
char an[205];


int main(){
    int kase = 0;
    scanf("%d", &T);
    while(T--){
        map<string, int> mp;
        int cnt = 0;
        scanf("%d", &c);
        scanf("%s", s1);
        scanf("%s", s2);
        scanf("%s", an);
        mp[an] = 1;
        while(1){
            int m = 0;
            for(int i = 0; i < c; i++){
                s12[m] = s2[i];
                m++;
                s12[m] = s1[i];
                m++;
            }
            s12[m] = '\0';
            cnt++;
            if(mp[s12] && strcmp(s12, an)){
                printf("%d -1\n", ++kase);
                break;
            }
            if(!strcmp(s12, an)){
                printf("%d %d\n", ++kase, cnt);
                break;
            }
            mp[s12] = 1;
            for(int i = 0; i < c; i++){
                s1[i] = s12[i];
                s2[i] = s12[i+c];
            }
            s1[c] = '\0';
            s2[c] = '\0';
        }
    }
return 0;
}

8 .poj3414 https://vjudge.net/problem/POJ-3414
题解:倒水问题, 记录路径, bfs

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <cstring>

using namespace std;

int A, B, C;

int v[105][105];

struct node{
    int a, b;
    int s, flag;
    int pre;
}cu[105*105];
int t[105*105];
int cnt;

int bfs(){
    queue<node> q;
    node now;
    now.a = now.b = 0;
    now.pre = -1;
    now.s = 0;
    q.push(now);
    v[0][0] = 1;
    while(q.size()){
        cnt++;
        cu[cnt] = q.front();
        q.pop();
        for(int i = 1; i <= 6; i++){
            if(i == 1){//FILL(1)
                now.a = A;
                now.b = cu[cnt].b;
                now.flag = 1;
            }
            else if(i == 2){//FILL(2)
                now.a = cu[cnt].a;
                now.b = B;
                now.flag = 2;
            }
            else if(i == 3){//DROP(1)
                now.a = 0;
                now.b = cu[cnt].b;
                now.flag = 3;
            }
            else if(i == 4){//DROP(2)
                now.a = cu[cnt].a;
                now.b = 0;
                now.flag = 4;
            }
            else if(i == 5){//POUR(1,2);
                if(cu[cnt].a + cu[cnt].b <= B){
                    now.b = cu[cnt].a + cu[cnt].b;
                    now.a = 0;
                }
                else{
                    now.a = cu[cnt].a + cu[cnt].b - B;
                    now.b = B;
                }
                now.flag = 5;
            }
            else if(i == 6){//POUR(2,1)
                if(cu[cnt].a + cu[cnt].b <= A){
                    now.a = cu[cnt].a + cu[cnt].b;
                    now.b = 0;
                }
                else{
                    now.b = cu[cnt].a + cu[cnt].b - A;
                    now.a = A;
                }
                now.flag = 6;
            } 
            if(!v[now.a][now.b]){
                v[now.a][now.b] = 1;
                now.s = cu[cnt].s + 1;
                now.pre = cnt;
                q.push(now);
            }
            if(now.a == C || now.b == C){
                int step = now.s;
                t[step] = now.flag;
                return step;
            }
        }
    }
    return -1;
}

int main(){
    scanf("%d%d%d", &A,&B,&C);
    int ans = bfs();
    if(ans == -1){
        printf("impossible\n");
    }
    else{
        int last = cnt;
        printf("%d\n", ans);
        for(int i = ans-1; i >= 1; i--){
            t[i] = cu[last].flag;
            last = cu[last].pre;
        }
        for(int i = 1; i <= ans; i++){
            if(t[i] == 1) printf("FILL(1)\n");
            else if(t[i] == 2) printf("FILL(2)\n");
            else if(t[i] == 3) printf("DROP(1)\n");
            else if(t[i] == 4) printf("DROP(2)\n");
            else if(t[i] == 5) printf("POUR(1,2)\n");
            else if(t[i] == 6) printf("POUR(2,1)\n");
        }
    }
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;
}

11 .poj3984 https://vjudge.net/problem/POJ-3984
题解:记录路径的bfs

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

int mp[10][10];
int v[10][10];
int dx[] = {0, 1, -1, 0};
int dy[] = {1, 0, 0, -1};

struct node{
    int x, y;
    int s, l[30]; 
};

node bfs(){
    int xx, yy;
    queue<node> q;
    node now, x;
    x.x = 0, x.y = 0, x.s = 0;
    q.push(x);
    v[0][0] = 1;
    while(q.size()){
        x = q.front();
        q.pop();
        if(x.x == 4 && x.y == 4){
            return x;
        }
        for(int i = 0; i < 4; i++){
            xx = x.x + dx[i];
            yy = x.y + dy[i];
            if(xx >= 0 && xx <= 4 && yy >= 0 && yy <= 4 && !v[xx][yy] && mp[xx][yy] == 0){
                now = x;
                now.x = xx, now.y = yy;
                v[now.x][now.y] = 1; 
                now.s = x.s + 1;
                now.l[x.s] = i;
                q.push(now);
            }
        }
    }
    return x;
}

int main(){
    for(int i = 0; i < 5; i++){
        for(int j = 0; j < 5; j++){
            scanf("%d", &mp[i][j]);
        }
    }
    node res = bfs();
    printf("(0, 0)\n");
    int x = 0 , y = 0;
    for(int i = 0; i < res.s; i++){
        x += dx[res.l[i]];
        y += dy[res.l[i]];
        printf("(%d, %d)\n", x, y);
    }
return 0;
}

12 .hdu1241 https://vjudge.net/problem/HDU-1241
题解:联通块计数

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

using namespace std;


int dx[] = {0, 0, -1, 1, -1, 1, -1, 1};
int dy[] = {-1, 1, 0, 0, -1, 1, 1, -1};
int n, m, cnt;
char mp[105][105];
int v[105][105];

bool check(int x, int y){
    if(v[x][y] || x < 0 || x >= n || y < 0 || y >= m || mp[x][y] == '*')
        return false;
    return true;
}


void dfs(int x, int y){
    int xx, yy;
    v[x][y] = cnt;
    for(int i = 0; i < 8; i++){
        xx = x + dx[i], yy = y + dy[i];
        if(check(xx, yy))
            dfs(xx, yy);
    }
}


int main(){
    while(scanf("%d%d", &n, &m) == 2){
        cnt = 0;
        memset(v, 0, sizeof(v));
        if(n == 0 && m == 0)
            break;
        for(int i = 0; i < n; i++){
            scanf("%s", mp[i]);
        }
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                if(!v[i][j] && mp[i][j] == '@'){
                    cnt++;
                    dfs(i, j);
                }
            }
        }
        printf("%d\n", cnt);
    }
return 0;
}

13 .hdu1495 https://vjudge.net/problem/HDU-1495
题解:倒水问题,有数学解法(见网上)

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

int S, N, M;

struct node{
    int a, b, c;
    int s;
};

bool v[105][105][105];

bool check(node x){
    if(x.a == x.b && x.a == S/2 || x.b == x.c && x.c == S/2 || x.a == x.c && x.c == S/2)
        return true;
    return false;
}

int bfs(){
    queue<node> q;
    node st;
    st.a = S, st.b = st.c = 0;
    st.s = 0;
    q.push(st);
    v[S][0][0] = 1;
    while(q.size()){
        node now = q.front();
        q.pop();
        if(check(now)){
            return now.s;
        }
        for(int i = 1; i <= 6; i++){
            node nxt;
            if(i == 1){//a->b
                if(now.a + now.b <= N){
                    nxt.b = now.a + now.b;
                    nxt.a = 0;
                    nxt.c = now.c;
                }
                else{
                    nxt.a = now.a + now.b - N;
                    nxt.b = N;
                    nxt.c = now.c;
                }
            }
            else if(i == 2){//a->c
                if(now.a + now.c <= M){
                    nxt.c = now.a + now.c;
                    nxt.a = 0;
                    nxt.b = now.b;
                }
                else{
                    nxt.a = now.a + now.c - M;
                    nxt.c = M;
                    nxt.b = now.b;
                }
            }
            else if(i == 3){//b->a
                if(now.b + now.a <= S){
                    nxt.a = now.b + now.a;
                    nxt.b = 0;
                    nxt.c = now.c;
                }
                else{
                    nxt.b = now.a + now.b - S;
                    nxt.a = S;
                    nxt.c = now.c;
                }
            }
            else if(i == 4){//b->c
                if(now.b + now.c <= M){
                    nxt.c = now.b + now.c;
                    nxt.b = 0;
                    nxt.a = now.a;
                }
                else{
                    nxt.b = now.b + now.c - M;
                    nxt.c = M;
                    nxt.a = now.a;
                }
            }
            else if(i == 5){//c->a
                if(now.c + now.a <= S){
                    nxt.a = now.c + now.a;
                    nxt.c = 0;
                    nxt.b = now.b;
                }
                else{
                    nxt.c = now.a + now.c - S;
                    nxt.a = S;
                    nxt.b = now.b;
                }
            }
            else if(i == 6){//c->b
                if(now.c + now.b <= N){
                    nxt.b = now.c + now.b;
                    nxt.c = 0;
                    nxt.a = now.a;
                }
                else{
                    nxt.c = now.c + now.b - N;
                    nxt.b = N;
                    nxt.a = now.a;
                }
            }
            if(!v[nxt.a][nxt.b][nxt.c]){
                nxt.s = now.s + 1;
                v[nxt.a][nxt.b][nxt.c] = 1;
                q.push(nxt);
            }
        }
    }
    return -1;
}

int main(){
    //freopen("D://Aduipai//data.txt", "r", stdin);
    //freopen("D://Aduipai//wa.txt", "w", stdout);
    int kase = 0;
    while(scanf("%d %d %d", &S, &N, &M) == 3){
        memset(v, 0, sizeof(v));
        if(!S && !N && !M)
            break;
        if(S % 2){
            printf("NO\n");
            continue;;
        }
        int ans = bfs();
        if(ans == -1){
            printf("NO\n");
        }
        else{
            printf("%d\n",ans);
        }
    }   

return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值