1. 程式人生 > >Kuangbin專題二搜尋進階

Kuangbin專題二搜尋進階

kuangbin專題二搜尋進階

A - Eight HDU - 1043

用康託展開來狀態壓縮,方便記錄路徑。另外路徑反著記。最後他孃的竟然打表,無恥。
八種方法


#include <string>
#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <cmath>
using namespace std
; typedef pair<int, int> P; #define N 9 #define M 400000 const int INF = 0x3f3f3f3f; #define fi first #define se second #define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++) struct node{ char ope; int fa; node(char c = 'l', int FA = -1):ope(c),fa(FA){} }; struct Node{ string s; int
can, n; Node(string S="", int Can=0, int NN=0):s(S), can(Can), n(NN){} }; char ch[N]; queue<Node> que; int fac[N]; node path[M]; string goal; char ope[] = "lrud"; int dx[] = {0, 0, 1, -1}; int dy[] = {1, -1, 0, 0}; int cantor(string num){ int ans = 0; rep(i, 0, N - 1) { int sm = 0; rep(j, i + 1
, N - 1) if(num[i] > num[j]) sm++; ans += sm * fac[N - i - 1]; } return ans; } void bfs() { que.push(Node(goal, 0, 8)); path[0].fa = 0; Node h; int x, y, xx, yy, index, tmp; string s; while(!que.empty()){ h = que.front(); que.pop(); rep(i, 0, 3){ x = h.n / 3; y = h.n % 3; xx = x + dx[i]; yy = y + dy[i]; index = xx * 3 + yy; if(xx < 0 || xx > 2 || yy < 0 || yy > 2) continue; if(index > 8 || index < 0) continue; s = h.s; swap(s[h.n], s[index]); tmp = cantor(s); if(path[tmp].fa != -1) continue; path[tmp] = node(ope[i], h.can); que.push(Node(s, tmp, index)); } } } int main() { //freopen("data.txt", "r", stdin); fac[0] = 1; rep(i, 1, N) fac[i] = fac[i - 1] * i; goal.clear(); rep(i, 1, N) goal += char('0' + i); bfs(); string num = ""; while(cin >> ch[0]){ num.clear(); rep(i, 1, N - 1) cin >> ch[i]; rep(i, 0, N - 1) if(ch[i] == 'x') num += '9'; else num += ch[i]; int s = cantor(num); if(path[s].fa == -1) puts("unsolvable"); else { while(s){ putchar(path[s].ope); s = path[s].fa; } putchar('\n'); } } return 0; }

B - Eight II HDU - 3567

寶寶心裡苦啊,這個程式碼調處來不容易啊。
我是用的網上的那個建立對映來寫的。具體細節和上一題差不多,就是建立了了對映,不得不說這個對映建立的真是騷氣。這題大大小小的錯誤卡了我這麼久,稍微寫一下注釋。

#include <string>
#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <cmath>
using namespace std;
typedef pair<int, int> P;
#define N 9
#define M 500000
const int INF = 0x3f3f3f3f;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

struct node{
  char ope;///operation 記錄操作
  int fa;///老爸。
  node(){fa = -1;}///初始化為-1於是祖先的fa值為-1
};
struct Node{
  char s[10];///tmd用string會超時
  int can, n, ind;///can是康託雜湊出來的值,n是9所在的下標,ind是祖宗的型別
  Node(){}
  Node(const char * S, int Can, int NN, int Ind):can(Can), n(NN), ind(Ind){
      rep(i, 0, 9) s[i] = S[i];
  }
  void set(const char * S, int Can, int NN, int Ind){
      rep(i, 0, 9) s[i] = S[i];;can = Can;n = NN; ind = Ind;
  }
};

queue<Node> que;
int fac[N];
node path[N][M];
char ope[] = "dlru";///這個玩意兒的方向要注意字典序
int dx[4] = {1, 0, 0, -1};
int dy[4] = {0, -1, 1, 0};
///一開始為了優化時間把各種操作寫出來了
char op[10][4] = {{0,2}, {0,1,2}, {0,1}, {0,2,3}, {0,1,2,3}, {0,1,3}, {2,3}, {1,2,3}, {1,3}};
int cnt[10] = {2,3,2,3,4,3,2,3,2};
char a[10], b[10];
int pa, pb, ca, cb;
int t, l;
char ans[M];
bool vis[N][M];
int ed[N];

int cantor(const char * num){
    int ans = 0;
    rep(i, 0, N - 1) {
        int sm = 0;
        rep(j, i + 1, N - 1) if(num[i] > num[j]) sm++;
        ans += sm * fac[N - i - 1];
    }
    return ans;
}

void bfs()
{
    Node tmp;
    tmp.set("123456789", ed[8] = cantor("123456789"), 8, 8); que.push(tmp); vis[8][ed[8]] = true;
    tmp.set("123456798", ed[7] = cantor("123456798"), 7, 7); que.push(tmp); vis[7][ed[7]] = true;
    tmp.set("123456978", ed[6] = cantor("123456978"), 6, 6); que.push(tmp); vis[6][ed[6]] = true;
    tmp.set("123459678", ed[5] = cantor("123459678"), 5, 5); que.push(tmp); vis[5][ed[5]] = true;
    tmp.set("123495678", ed[4] = cantor("123495678"), 4, 4); que.push(tmp); vis[4][ed[4]] = true;
    tmp.set("123945678", ed[3] = cantor("123945678"), 3, 3); que.push(tmp); vis[3][ed[3]] = true;
    tmp.set("129345678", ed[2] = cantor("129345678"), 2, 2); que.push(tmp); vis[2][ed[2]] = true;
    tmp.set("192345678", ed[1] = cantor("192345678"), 1, 1); que.push(tmp); vis[1][ed[1]] = true;
    tmp.set("912345678", ed[0] = cantor("912345678"), 0, 0); que.push(tmp); vis[0][ed[0]] = true;

    Node h;
    int xx, yy, index, tp;
    char s[10];
    while(!que.empty()){
        h = que.front(); que.pop();
        rep(i, 0, cnt[h.n] - 1) {
            xx = h.n / 3 + dx[op[h.n][i]]; yy = h.n % 3 + dy[op[h.n][i]];
            index = xx * 3 + yy;

            strcpy(s, h.s);
            swap(s[h.n], s[index]);

            tp = cantor(s);
            if(vis[h.ind][tp]) continue;

            vis[h.ind][tp] = true;
            path[h.ind][tp].ope = ope[op[h.n][i]];
            path[h.ind][tp].fa = h.can;
            que.push(Node(s, tp, index, h.ind));
        }
    }
}

int main()
{
    //freopen("data.txt", "r", stdin);

    fac[0] = 1;
    rep(i, 1, N) fac[i] = fac[i - 1] * i;
    bfs();

    scanf("%d", &t);
    rep(Case, 1, t){
        scanf("%s%s", a, b);
    ///這裡多寫了個elsemmp
        rep(i, 0, N - 1) if(a[i] == 'X') a[i] = '9', pa = i;
        rep(i, 0, N - 1) if(b[i] == 'X') b[i] = '9', pb = i;

        int cast[10], id = 1;
        rep(i, 0, N - 1) if(a[i] != '9')cast[a[i] - '0'] = id++;
        else cast[9] = 9;

        rep(i, 0, N - 1) b[i] = cast[b[i] -'0'] + '0';

        cb = cantor(b);
        l = 0;
        while(cb != ed[pa]){
            ans[l++] = path[pa][cb].ope;
            cb = path[pa][cb].fa;///這裡寫成了ca
        }
        printf("Case %d: %d\n", Case, l);
        for(int i = l - 1; i >= 0; i--) putchar(ans[i]);
        putchar('\n');
    }

    return 0;
}

C - 哈密頓繞行世界問題 HDU - 2181

突然來了一道簡單題。

#include <string>
#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
using namespace std;
typedef pair<int, int> P;
#define N 21
#define M 500000
const int INF = 0x3f3f3f3f;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int g[N][3], ans[N];
bool vis[N];
int m, l;
int a, b, c;

void dfs(int fa, int deep)
{
    if(deep == N - 1){
        printf("%d:  ", ++l);
        rep(i, 0, 19) printf("%d ", ans[i]);
        printf("%d\n", m);
        return;
    }

    if(vis[a] && vis[b] && vis[c]) return;

    rep(i, 0, 2) {
        if(!vis[g[fa][i]]){
            vis[g[fa][i]] = true;
            ans[deep] = g[fa][i];
            dfs(g[fa][i], deep + 1);
            vis[g[fa][i]] = false;
        }
    }
}

int main()
{
    //freopen("data.txt", "r", stdin);

    rep(i, 1, 20) rep(j, 0, 2) scanf("%d", &g[i][j]);
    rep(i, 1, 20) sort(g[i], g[i] + 3);

    while(~scanf("%d", &m) && m){
        a = g[m][0]; b = g[m][1]; c = g[m][2];
        memset(vis, false, sizeof vis);
        l = 0;
        ans[0] = m;
        vis[m] = true;
        dfs(m, 1);
    }

    return 0;
}

D - Escape HDU - 3533

這題本來是普通的寬搜,只是加上了一個時間維度。
因為機智的直接百度,所以我看到了子彈不能穿過城堡這個點。
mmp寬搜裡忘了寫vis導致ME了好久。
我是先把子彈預處理出來了,直接標記vis,百度的時候也有走到哪兒就判斷一下的,資料比較弱可能吧。

#include <string>
#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
using namespace std;
//typedef pair<int, int> P;
#define N 101
#define M 1001
const int INF = 0x3f3f3f3f;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

bool vis[N][N][M];
int g[N][N];
int dx[] = {0, 0, 0, 1, -1};
int dy[] = {0, 1, -1, 0, 0};
int n, m, k, d, t, v, x, y;
char c;
struct node{
  int c, t, v, x, y;
}ope[N];
struct P{
  int first, second, d;
  P(int x=0, int y=0, int d=0):first(x),second(y), d(d){}
};
queue<P> que;

bool ok(int x, int y){
    return 0 <= x && x <= n && 0 <= y && y <= m;
}
int geted(node & t)
{
    int c = t.c, x = t.x, y = t.y;
    int cnt = 0;
//cout << c << ' ' << ' ' << t.v << ' ' << x << ' ' << y << endl;
    while(ok(x + dx[c], y + dy[c])){
        x += dx[c]; y += dy[c];  //cout << "xy " << x << ' ' << y << ' ' endl;
        if(g[x][y]) break;
        if(c == 1 && (y - t.y) % t.v == 0) cnt++;
        else if(c == 2 && (t.y - y) % t.v == 0) cnt++;
        else if(c == 3 && (x - t.x) % t.v == 0) cnt++;
        else if(c == 4 && (t.x - x) % t.v == 0) cnt++;
     }
     return cnt;
}

int bfs()
{
    while(!que.empty()) que.pop();
    que.push(P(0, 0, d));

    while(!que.empty()){
        P h = que.front(); que.pop();
        if(h.fi == n && h.se == m) return d - h.d;
        if(h.d <= 0 || h.d < (m + n - h.fi - h.se - 1)) continue;
    //   cout << h.d;
        rep(i, 0, 4){
            x = h.fi + dx[i]; y = h.se + dy[i];
            if(!ok(x, y) || vis[x][y][d - h.d + 1] || g[x][y]) continue;
//if(h.d == 9) cout <<"i "<<i<<endl;
            vis[x][y][d - h.d + 1] = true;
            que.push(P(x, y, h.d - 1));
        }
    }
    return -1;
}

int main()
{
    //freopen("data.txt", "r", stdin);
    while(~scanf("%d%d%d%d", &n, &m, &k, &d)){
        memset(vis, false, sizeof vis);
        memset(g, 0, sizeof g);
        rep(i, 0, k - 1) {
            cin >> c;
            if(c == 'E') ope[i].c = 1;
            else if(c == 'W') ope[i].c = 2;
            else if(c == 'S') ope[i].c = 3;
            else if(c == 'N') ope[i].c = 4;
            cin >> ope[i].t >> ope[i].v >> ope[i].x >> ope[i].y;
            g[ope[i].x][ope[i].y] = 1;
        }

        int x, y;
        rep(i, 0, k - 1) {
            c = ope[i].c;
            int ed = geted(ope[i]);//cout << "ed"<<ed << endl;
            x = ope[i].x; y = ope[i].y;
            rep(j, 1, ed){
                x += dx[c] * ope[i].v; y += dy[c] * ope[i].v;
              //  cout << x << ' ' << y << ' ' << j << endl;
                for(int z = 0; j + z * ope[i].t <= d; z++)
                    vis[x][y][j + z * ope[i].t] = true;
            }
        }
//cout << vis[2][0][4] << ' ' << vis[2][1][7]<< endl;
        int ans = bfs();
        if(ans == -1) puts("Bad luck!");
        else printf("%d\n", ans);
    }

    return 0;
}

E - DNA sequence HDU - 1560

我就寫過劉汝佳上的一道迭代加深搜尋,所以直接學的網上的程式碼(不百度根本不知道只是IDA*,還覺得是模擬)。
學習於這裡

#include <string>
#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
using namespace std;
typedef pair<int, int> P;
#define N 10
#define M 1001
const int INF = 0x3f3f3f3f;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

char s[10][5], c[] = "ACGT";
int n, m, sum, res, t;
bool ans;
int len[10], pos[10];

int getlen()
{
    int mx = 0;
    rep(i, 0, n - 1) mx = max(mx, len[i] - pos[i]);
    return mx;
}

int dfs(int deep)
{
    int t = getlen();
    if(t + deep > res) return t + deep - res;
    if(!t){
        ans = true; return 0;
    }

    int mx = 0, tmp[10];
    memcpy(tmp, pos, sizeof pos);
    rep(i, 0, 3){
        bool flag = false;
        rep(j, 0, n - 1) if(s[j][pos[j]] == c[i])
            flag = true, pos[j]++;
        if(flag){
            int t = dfs(deep + 1);
            if(ans) return 0;
            mx = max(t, mx);
            memcpy(pos, tmp, sizeof tmp);
        }
    }
    return mx;
}

void ida()
{
    int t = 0;
    ans = false;
    while(true){
        t = dfs(0);
        if(ans) return;
        res += t;
    }
}

int main()
{
    ///freopen("data.txt", "r", stdin);

    scanf("%d", &t);
    while(t--){
        scanf("%d", &n);
        res = 0;

        rep(i, 0, n - 1){
            scanf("%s", s[i]);
            len[i] = strlen(s[i]);
            res = max(res, len[i]);
            pos[i] = 0;
        }

        ida();
        printf("%d\n", res);
    }

    return 0;
}

F - Magic Cube ZOJ - 2477

tmd這輩子都不寫模擬題了要老命。
吐槽vj的顯示,爬資料就不能好好顯示嗎。
真正的字母

vj的字母

預處理出所有可能的操作,六個面,每個面只有2種,一共12
種。不超過5層,就算12^5的複雜度,直接IDA*一層一層來。

#include <string>
#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
using namespace std;
typedef pair<int, int> P;
#define N 55
#define M 1001
const int INF = 0x3f3f3f3f;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
///*
//         1  2  3
//         4  5  6
//         7  8  9
//10 11 12 13 14 15 16 17 18 19 20 21
//22 23 24 25 26 27 28 29 30 31 32 33
//34 35 36 37 38 39 40 41 42 43 44 45
//         46 47 48
//         49 50 51
//         52 53 54
//*/
int cent[7] = {23, 26, 29, 32, 5, 50};
int face[7][10] = {
{10,11,12,22,23,24,34,35,36},
{13,14,15,25,26,27,37,38,39},
{16,17,18,28,29,30,40,41,42},
{19,20,21,31,32,33,43,44,45},
{1,2,3,4,5,6,7,8,9},
{46,47,48,49,50,51,52,53,54}
};
int change[12][20] = {       
                   {1,4,7,13,25,37,46,49,52,21,33,45,10,11,12,24,36,35,34,22},
                   {45,33,21,1,4,7,13,25,37,52,49,46,34,22,10,11,12,24,36,35},
                   {7,8,9,16,28,40,48,47,46,36,24,12,13,14,15,27,39,38,37,25},
                   {36,24,12,7,8,9,16,28,40,48,47,46,37,25,13,14,15,27,39,38},
                   {9,6,3,19,31,43,54,51,48,39,27,15,16,17,18,30,42,41,40,28},
                   {39,27,15,9,6,3,19,31,43,54,51,48,40,28,16,17,18,30,42,41},
                   {42,30,18,3,2,1,10,22,34,52,53,54,19,20,21,33,45,44,43,31},
                   {52,53,54,42,30,18,3,2,1,10,22,34,43,31,19,20,21,33,45,44},
                   {15,14,13,12,11,10,21,20,19,18,17,16,1,2,3,6,9,8,7,4},
                   {18,17,16,15,14,13,12,11,10,21,20,19,7,4,1,2,3,6,9,8},
                   {37,38,39,40,41,42,43,44,45,34,35,36,46,47,48,51,54,53,52,49},
                   {34,35,36,37,38,39,40,41,42,43,44,45,52,49,46,47,48,51,54,53}
                  } ;


char s[N];
int t, res;
int a[10], b[10];

char getch(){
    char c; while((c = getchar()) == ' ' || c == '\n');
    return c;
}

int geth(char * s)
{
    int mx = 0;
    rep(i, 0, 5) rep(j, 0, 8)
        if(s[face[i][j]] != s[cent[i]]) mx++;
    return (mx + 11) / 12;
}

bool dfs(int deep)
{
    int t = geth(s);
    if(t + deep > res) return false;
    if(!t) return true;

    char tmp[N];
    memcpy(tmp, s, sizeof s);
    rep(i, 0, 11){
        rep(j, 0, 19) s[change[i][j]] = tmp[change[i^1][j]];

        a[deep] = i / 2;
        b[deep] = i & 1?-1:1;

        if(dfs(deep + 1)) return true;
        memcpy(s, tmp, sizeof tmp);
    }
    return false;
}

void ida()
{
    res = geth(s);

    if(!res) {printf("0\n"); return;}
    res = 1;
    while(res <= 5){
        if(dfs(0)){
            printf("%d\n", res);
            rep(i, 0, res - 1) printf("%d %d\n", a[i], b[i]);
            return;
        }
        res++;
    }
    printf("-1\n");
}

int main()
{
   // freopen("data.txt", "r", stdin);

    scanf("%d", &t);
    while(t--){
        rep(i, 1, N - 1) s[i] = getch();
        ida();
    }

    return 0;
}

H - Gap HDU - 1067

雜湊雜湊,太難了雜湊,上次我雜湊寬搜是什麼時候了。。。還是做的太少了。(其實map就挺好)。
轉載連結

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<utility>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<iterator>
#include<stack>
using namespace std;
const int INF=1e9+7;
const double eps=1e-8;
typedef __int64 LL;
const LL mod=1000007;
typedef pair<int, int> P;
#define N 801
#define M 1001
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int maze[4][8];
LL Hash[mod];
LL base[32];
struct node{
    int px[4],py[4];
    int S[4][8];
    int dist;
}Nod[100005];
int id;
queue<int> que;

int goal[4][8]={
{ 11,12,13,14,15,16,17,0 },
{ 21,22,23,24,25,26,27,0 },
{ 31,32,33,34,35,36,37,0 },
{ 41,42,43,44,45,46,47,0 }
};
LL G;

int GetId(int x,int y){ return x*8+y; }

LL GetHash(int S[4][8])
{
    LL ret=0;
    for(int i=0;i<4;i++)
        for(int j=0;j<8;j++) ret+=(LL)S[i][j]*base[GetId(i,j)];
    return ret;
}
bool InsertHash(LL val){
   LL v=val%mod;
   while(Hash[v]!=-1&&Hash[v]!=val)  v=(v+10)%mod;
   if(Hash[v]==-1){ Hash[v]=val; return true; }
   return false;
}

void Change_S(node& e,int x,int y,int pick,int k)
{
    rep(i, 0, 3) rep(j, 0, 7) if(e.S[i][j]==pick){
        e.S[i][j]=0; e.S[x][y]=pick; e.px[k]=i; e.py[k]=j;
        return;
    }
}
void AddNode(int now)
{
    node& e = Nod[now];
    rep(i, 0, 3){
        int x=e.px[i], y=e.py[i];
        int pre = e.S[x][y - 1];
        if(pre == 0 || e.S[x][y - 1] % 10 == 7) continue;

        node t = e;
        t.dist++;
        Change_S(t, x, y, e.S[x][y - 1] + 1, i);
        LL nowG=GetHash(t.S);
        if(!InsertHash(nowG)) continue;

        int cur=id++;
        Nod[cur]=t;
        que.push(cur);
    }
}
int bfs()
{
    rep(i, 0, 3) rep(j, 1, 7){
        int a=maze[i][j]/10;
        int b=maze[i][j]%10;
        if(b==1) { maze[a-1][0]=maze[i][j]; maze[i][j]=0; }
    }
    memset(Hash,-1,