SCUT ACM PLACTICE # 3 二进制枚举,深搜,广搜


Links:https://vjudge.net/contest/145674#overview


A - 搜索 初心者向 HDU - 2553

简单搜索n皇后,主要是要处理判断是否能放置的问题。
这次我用了四个数组来判断行,列,主对角和副对角是否已经有棋子。

#include<iostream>
#include<string.h>
#include<string>
#include<math.h>
#include<stdio.h>
using namespace std;
int n;
bool h[50], l[50], z[50], f[50];
int ans[15];

int dfs(int x, int y){

    if (y == n){ return 1; }
    int ans = 0;
    h[x] = 1, l[y] = 1, z[x + y] = 1, f[x - y + 20] = 1;
    for (int i = 1; i <= n; i++){
        if (h[i] == 0 && l[y + 1] == 0 && z[i + y + 1] == 0 && f[i - y - 1 + 20] == 0){
            ans += dfs(i, y + 1);
        }
    }
    h[x] = 0, l[y] = 0, z[x + y] = 0, f[x - y + 20] = 0;

    return ans;
}

int main(){
    for (int i = 1; i <= 10; i++){
        for (int j = 1; j <= i; j++){
            n = i;
            ans[i] += dfs(j, 1);
        }
    }
    while (~scanf("%d", &n),n!=0){
        printf("%d\n", ans[n]);
    }
    return 0;
}

B - 搜索 中级者向 POJ - 3278

广搜,能够对当前数字+1,-1,*2,求最小步骤从初始数字到终末数字。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<queue>
using namespace std;
int fx, fy;
int astep;
int v[300005];
struct point{
    int x;
    int s;
}beg;
queue<point> que;
int bfs(){
    int ans = -1;
    int k = fy > fx ? (fy - fx) : (fx - fy);
    while (!que.empty()){
        point cnt = que.front();
        que.pop();
        if (astep != -1 && cnt.s > astep||cnt.x<0||cnt.x>105000||cnt.s>k){ continue; }
        if (cnt.x == fy){ 
            if (astep == -1){ astep = cnt.s; }
            else{ astep = astep < cnt.s ? astep : cnt.s; }
            continue; }
        if (v[cnt.x + 1] == 0){
            que.push({ cnt.x + 1, cnt.s + 1 });
            v[cnt.x + 1] = 1;
        }
        if (cnt.x-1>=0&&v[cnt.x - 1] ==0){
            que.push({ cnt.x - 1, cnt.s + 1 });
            v[cnt.x -1] = 1;
            }
        if (cnt.x != 0 && v[cnt.x * 2] == 0){
            que.push({ cnt.x * 2, cnt.s + 1 }); 
            v[cnt.x*2] = 1; }
    }
    return ans;
}


int main(){
    scanf("%d%d", &fx, &fy);
    astep = -1;
    beg.x = fx, beg.s = 0;
    que.push(beg);
    bfs();
    printf("%d",astep );
    return 0;
}

C - 搜索 中级者向 POJ - 2488

八方向跳棋,求最终整个棋盘都跳满的路径,要求输出路径比较麻烦,dfs过程中在相应的格子记录上这是跳的第几步就行了。

#include<iostream>
#include<string.h>
#include<string>
#include<algorithm>
#include<stdio.h>
using namespace std;
int fx, fy,total;
bool r;
int v[24][24];
int dx[8] = {-1,1,-2,2,-2,2,-1,1};
int dy[8] = {-2,-2,-1,-1,1,1,2,2};

void dfs(int x,int y,int n){
    if (r == false)
    v[x][y] = n;
    if (n == total){
        r = true; return; }
    for (int i = 0; i < 8; i++){
        int nx = x + dx[i], ny = y + dy[i];
        if (nx>0 && nx <= fx&&ny > 0 && ny <= fy&&v[nx][ny] == 0&&r==false){
            dfs(nx, ny, n + 1);
            if (r == true){ break; }
        }
    }   
    if (r==false)
    v[x][y] = 0;
}

void pf(int x, int y,int n){
    putchar(y + 64);
    printf("%d", x);
    if (n == total){ return; }
    for (int i = 0; i < 8; i++){
        if (v[x + dx[i]][y + dy[i]] == n + 1){
            pf(x + dx[i], y + dy[i], n + 1);
        }
    }
}

int main(){
    int t;
    scanf("%d", &t);
    for(int k=1;k<=t;k++){
        int ax, ay;
        r = false;
        memset(v, 0, sizeof(v));
        scanf("%d%d", &fx, &fy);
        total = fx*fy;
        for (int i = 1; i <= fx; i++){
            for (int j = 1; j <= fy; j++){
                dfs(i, j,1);
                if (r == true){
                    ax = i, ay = j;
                    break; }
            }
            if (r == true)break;
        }

        printf("Scenario #%d:\n", k);
        if (r == false){ printf("impossible\n\n"); }
        else{
            pf(ax, ay,1);
            printf("\n\n");
        }
    }
    return 0;
}

D - 搜索 初心者向

三维地图bfs最短路径,方向变成6个。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<queue>
using namespace std;
int l, r, c,ans;
int map[32][32][32];
bool v[32][32][32];
int dl[6] = { 0, 0, 0, 0, 1, -1 };
int dx[6] = { -1, 0, 0, 1, 0, 0 };
int dy[6] = { 0, -1, 1, 0, 0, 0 };
struct point{
    int l;
    int x;
    int y;
    int s;
}beg;
queue<point> que;
int bfs(){
    int ans = -1;
    while (!que.empty()){
        point cnt = que.front();
        que.pop();
        if (map[cnt.l][cnt.x][cnt.y]=='E'){ ans = cnt.s; break; }
        for (int i = 0; i < 6; i++){
            point np={ cnt.l + dl[i], cnt.x + dx[i], cnt.y + dy[i], cnt.s + 1 };
            if (np.l >= 0 && np.l<l&&np.x>=0 && np.x<r&&np.y>=0 && np.y < c){
                if (map[np.l][np.x][np.y] != '#'&&v[np.l][np.x][np.y]==0){
                    que.push(np);
                    v[np.l][np.x][np.y] = 1;
                }
            }
        }
    }
    while (!que.empty()){
        que.pop();
    }
    return ans;
}

int main(){
    while (scanf("%d%d%d", &l, &r, &c)){
        memset(v, 0, sizeof(v));
        getchar();
        if (l == 0){ return 0; }
        for (int i = 0; i < l; i++){
            for (int j = 0; j < r; j++){
                for (int k = 0; k < c; k++){
                    map[i][j][k]=getchar();
                    if (map[i][j][k] == 'S'){
                        beg.l = i, beg.x = j, beg.y = k,beg.s=0;
                        v[i][j][k] = 1;
                    }
                }
                getchar();
            }
            getchar();
        }
        que.push(beg);
        int ans = bfs();
        if (ans == -1){
            printf("Trapped!\n");
        }
        else{
            printf("Escaped in %d minute(s).\n",ans);
        }
    }
    return 0;
}

E - 搜索(DFS) 初心者向

连通块计数,经典的dfs

#include<iostream>
#include<string.h>
#include<string>
#include<math.h>
#include<stdio.h>
using namespace std;
int n, m;
char map[105][105];
int dx[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
int dy[8] = { -1, 0, 1, -1, 1, -1, 0, 1 };

void dfs(int x, int y){
    map[x][y] = '.';
    for (int i = 0; i < 8; i++){
        int nx = x + dx[i], ny = y + dy[i];
        if (nx >= 0 && nx < n&&ny >= 0 && ny < m&&map[nx][ny] == 'W'){
            dfs(nx, ny);
        }
    }
}

int main(){
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++){
        getchar();
        for (int j = 0; j < m; j++){
            map[i][j] = getchar();
        }
    }

    int ans = 0;
    for (int i = 0; i < n; i++){
        for (int j = 0; j < m; j++){
            if (map[i][j] == 'W'){

                dfs(i, j);
                ans++;
            }
        }
    }
    printf("%d", ans);

    return 0;
}

F - 搜索(BFS)+模拟 中级者向 POJ - 3083

给出地图求三种走法的路径:左扶墙,右扶墙,最短路。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<queue>
using namespace std;
int fx, fy;
char map[45][45];
bool v[45][45];
int dx1[4] = { 0, -1, 0, 1, };
int dy1[4] = { 1, 0, -1, 0, };
int dx2[4] = { 0, -1, 0, 1, };
int dy2[4] = { -1, 0, 1, 0, };
struct point{
    int x;
    int y;
    int s;
}beg;
queue<point> que;
int bfs(){
    int ans = -1;
    while (!que.empty()){
        point cnt = que.front();
        que.pop();
        if (map[cnt.x][cnt.y] == 'E'){ ans = cnt.s; break; }
        for (int i = 0; i < 4; i++){
            point np = { cnt.x + dx1[i], cnt.y + dy1[i], cnt.s + 1 };
            if (np.x >= 0 && np.x<fx&&np.y >= 0 && np.y < fy){
                if (map[np.x][np.y] != '#'&&v[np.x][np.y] == 0){
                    que.push(np);
                    v[np.x][np.y] = 1;
                }
            }
        }
    }
    while (!que.empty()){
        que.pop();
    }
    return ans;
}

int dfs(point cnt,int dir){

    if (map[cnt.x][cnt.y] == 'E'){
        return cnt.s;
    }
    for (int i = dir-1;; i++){
        int ci = i < 0 ? i + 4:i;
        point newp = { cnt.x + dx1[ci % 4], cnt.y + dy1[ci % 4], cnt.s + 1 };
        if (newp.x >= 0 && newp.x < fx&&newp.y >= 0 && newp.y < fy&&map[newp.x][newp.y] != '#'){

            dfs(newp, i);
            break;
        }
    }
}

int idfs(point cnt, int dir){

    if (map[cnt.x][cnt.y] == 'E'){
        return cnt.s;
    }
    for (int i = dir-1;; i++){
        int ci = i < 0 ? i + 4 : i;
        point newp = { cnt.x + dx2[ci % 4], cnt.y + dy2[ci % 4], cnt.s + 1 };
        if (newp.x >= 0 && newp.x < fx&&newp.y >= 0 && newp.y < fy&&map[newp.x][newp.y] != '#'){

            idfs(newp, i);
            break;
        }
    }
}

int main(){
    int t;
    scanf("%d", &t);
    while (t--){
        scanf("%d%d", &fy, &fx);
        memset(v, 0, sizeof(v));
        getchar();
        for (int i = 0; i < fx; i++){
            for (int j = 0; j < fy; j++){
                map[i][j] = getchar();
                if (map[i][j] == 'S'){
                    beg.x = i, beg.y = j, beg.s = 1;
                    v[i][j] = 1;
                }
            }
            getchar();
        }

        que.push(beg);
        int ans = bfs();
        int ans1 = dfs(beg,0);
        int ans2 = idfs(beg, 0);
        printf("%d %d %d\n", ans2, ans1, ans);
    }
    return 0;
}

G - 欧拉图 初心者向 HDU - 1878

判断欧拉回路的题。并查集判连通。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
using namespace std;
int n, m;
int point[1005];
int f[1005];
int F(int x){
    if (f[x] == x)return x;
    else{ return f[x] = F(f[x]); }
}

int main(){
    int x, y;
    while (~scanf("%d", &n)){
        if (n == 0){ return 0; }
        scanf("%d", &m);
        for (int i = 1; i <= n; i++){
            f[i] = i;
        }
        memset(point, 0, sizeof(point));
        for (int j = 0; j < m; j++){
            scanf("%d%d", &x, &y);
            point[x]++;
            point[y]++;
            f[F(x)] = F(y);
        }

        int ji = 0;
        int ff = F(1);
        for (int i = 1; i <= n; i++){
            if ((point[i] % 2) != 0||F(i)!=ff){
                ji = 1; break;
            }
        }
        if (ji == 0){ printf("%d\n",1); }
        else{ printf("%d\n",0); }
    }
    return 0;
}

H - 欧拉图 中级者向 POJ - 2230

就是输出一条欧拉回路。

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <stdio.h>
using namespace std;
#define maxn 50000+10
int n, m;
struct Edge
{
    int to;
    bool vis;
};
vector<Edge>G[maxn];

void euler(int u)
{
    int num = G[u].size();
    for (int i = 0; i < num; i++){
        if (G[u][i].vis == 0){
            G[u][i].vis = 1;
            euler(G[u][i].to);
        }
    }
    printf("%d\n", u);
}
int main()
{
    scanf("%d%d", &n, &m);
    int x, y;
    for (int i = 0; i < m; i++){
        scanf("%d%d", &x, &y);
        Edge a = { y, 0 };
        Edge b = { x, 0 };
        G[x].push_back(a);
        G[y].push_back(b);
    }

        euler(1);
    return 0;
}

I - 欧拉图 上级者向 POJ - 1780

要求把所有可能的密码已最短长度也就是最大的重叠度输出出来,对于n位的密码,答案每往后输出一位,就会与前n-1位构成一个新密码,转换成以n-1位数字为点的欧拉回路,因为除了最后n-1位,一但有一个n-1位数字后面新增0-9都已经在前面输出过了,那么就无法只新增一位来构造一个新密码。
要求非递归,看了别人的代码看了好久才看懂。

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

int n, ppow[] = { 1, 10, 100, 1000, 10000, 100000, 1000000 };
int cnt[1000000], stack[1000010];
bool vis[1000000];
void dfs(){
    memset(vis, 0, sizeof(vis));
//  vis[0] = 1;
    memset(cnt, 0, sizeof(cnt));
    int top = -1;
    stack[++top] = 0;
    int total = ppow[n];
    while (top!=total){
        int v = stack[top];
        if (cnt[v] ==10 ){
            vis[v] = 0; cnt[v] = 0;
            top--;
            continue;
        }
        int newn = (v * 10 + cnt[v]) % ppow[n];
        cnt[v]++;
        if (vis[newn]){ continue; }
        vis[newn] = 1;
        stack[++top] = newn;
    }
    for (int i = 1; i <= top; ++i) putchar(stack[i] % 10 + '0');
}
int main(){
    while (~scanf("%d", &n) && n){
        for (int i = 1; i<n; ++i) putchar('0');
        dfs();
        putchar('\n');
    }
    return 0;
}

J - 二叉树 中级者向

给出二叉树的前序中序遍历,要求给出后序遍历的结果。分治递归就行。

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <stdio.h>
using namespace std;
int n;
int pre[1005];
int in[1005];
int cou,acount;
void findans(int beg, int end){
    if (beg == end){
        return;
    }
    int cnt = pre[cou++];

    int mid;
    for (int i = beg; i < end; i++){
        if (in[i] == cnt){
            mid = i;
            break;
        }
    }
    findans(beg, mid);
    findans(mid + 1, end);
    printf("%d", in[mid]);
    if (acount <n-1){ printf(" "); }
    acount++;
}

int main()
{
    while (~scanf("%d", &n)){
        cou = 0,acount=0;
        for (int i = 0; i < n; i++){
            scanf("%d", &pre[i]);
        }
        for (int i = 0; i < n; i++){
            scanf("%d", &in[i]);
        }
        findans(0, n );
        printf("\n");
    }
}

K - 二进制枚举 初心者向

输出比给定数字大的只包含4和7且4和7的数量相等的最小数字,枚举每一位是4或7就行。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
using namespace std;
long long num;
long long ans;
void dfs(long long n,int fn,int sn){

    if (ans!=0&&n >ans||n>num*100 ){ return; }
    if (fn == sn&&n>=num){ 
        if (ans == 0){ ans = n; }
        else{ ans = ans < n ? ans : n; }
    }
    dfs(n * 10 + 4,fn+1,sn);
    dfs(n * 10 + 7,fn,sn+1);
}

int main(){
    while (cin >> num){
        ans = 0;
        dfs(0, 0, 0);
        cout << ans << endl;
    }
    return 0;
}

L - 二进制枚举 初心者向 HDU - 1557

简单的枚举题。

#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
int n;
int p;
int v[25];

int dfs(int x, int y,int num){

    if (y == n-1){
        if (num > p && (num - v[x] <= p)){ return 1; }
        else {return 0;}
    }
    int ans = 0;
    if (y+1 == x){
        ans += dfs(x, y + 1, num + v[y+1]);
    }
    else{
        ans += dfs(x, y + 1, num);
        ans += dfs(x, y + 1, num + v[y+1]);
    }
    return ans;
}

int main(){
    int t;
    cin >> t;
    while (t--){
        int total = 0;
        cin >> n;
        for (int i = 0; i < n; i++){
            cin >> v[i];
            total += v[i];
        }
        p = total / 2;

        for (int i = 0; i < n; i++){
            cout << dfs(i, -1, 0);

            if (i < n - 1){ cout << " "; }
        }
        cout << endl;
    }
    return 0;
}

M - 二进制枚举 初心者向 CodeForces - 202A

求字典序最大的回文字串。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
using namespace std;
string raw, ans;
int length;

bool pal(string a){
    int len = a.length();
    bool ans = true;
    for (int i = 0; i < len / 2; i++){
        if (a[i] != a[len - i - 1]){
            ans = false;
            break;
        }
    }
    return ans;
}

void dfs(int x,string cnt){
    if (pal(cnt)){
        if (ans == " "||cnt>ans){
            ans = cnt;
        }
    }
    if (x == length - 1){ return; }
    dfs(x + 1, cnt + raw[x + 1]);
    dfs(x + 1, cnt);
}

int main(){
    cin >> raw;
    ans = " ";
    length = raw.length();
    dfs(-1, "");
    cout << ans;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值