Kuangbin專題二搜尋進階
阿新 • • 發佈:2018-12-24
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的顯示,爬資料就不能好好顯示嗎。
預處理出所有可能的操作,六個面,每個面只有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,