# 2014 UESTC暑前集训搜索专题解题报告

A.解救小Q

BFS。每次到达一个状态时看是否是在传送阵的一点上，是则传送到另一点即可。

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

char mp[52][52];

struct status
{
int x,y;
int l;
};

int vis[52][52];

struct transport
{
int x1,y1;  //初始点
int x2,y2;  //传送目标点
int flag;
}a[27];

int n,m;
int pathx[4]={0,1,0,-1};
int pathy[4]={-1,0,1,0};

bool OK(int nx,int ny)
{
return nx>=0&&ny>=0&&nx<n&&ny<m;
}

int bfs(int x,int y)
{
status now,next;
queue<status> que;
now.x=x;
now.y=y;
now.l=0;
vis[now.x][now.y]=1;
que.push(now);
while(!que.empty())  //队列非空
{
now = que.front();
que.pop();
for(int i=0;i<4;i++)
{
int nx=now.x+pathx[i];
int ny=now.y+pathy[i];
if(vis[nx][ny] || !OK(nx,ny))
continue;
if(mp[nx][ny]=='Q')
return now.l+1;
if(mp[nx][ny]!='#')
{
if(mp[nx][ny]>='a'&&mp[nx][ny]<='z')
{
int h=mp[nx][ny]-'a';
if(a[h].x1!=nx||a[h].y1!=ny)  //初始点和目标点可以互换
{
next.x=a[h].x1;
next.y=a[h].y1;
}
else
{
next.x=a[h].x2;
next.y=a[h].y2;
}
next.l=now.l+1;
que.push(next);
}
else
{
next.x=nx;
next.y=ny;
next.l=now.l+1;
que.push(next);
}
vis[nx][ny]=1;
}
}
}
return -1;
}

int main()
{
int T,x,y;
int N,M;
scanf("%d",&T);
while(T--)
{
memset(vis,0,sizeof(vis));
memset(mp,0,sizeof(mp));
for(int j=0;j<27;j++)
a[j].flag=0;
scanf("%d%d",&N,&M);
n=N;
m=M;
getchar();
for(int i=0;i<N;i++)
{
for(int j=0;j<M;j++)
{
scanf("%c",&mp[i][j]);
if(mp[i][j]=='L')
{
x=i;
y=j;
}
if(mp[i][j]>='a'&&mp[i][j]<='z')
{
int h=mp[i][j]-'a';
if(a[h].flag==0)
{
a[h].x1=i;
a[h].y1=j;
a[h].flag=1;
}
else if(a[h].flag==1)
{
a[h].x2=i;
a[h].y2=j;
}
}
}
getchar();
}
printf("%d\n",bfs(x,y));
}
return 0;
}
View Code

B.方老师开橙卡

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define Mod 1000000007
using namespace std;
#define N 50007

int Scheck(ll ka,ll n)
{
while(ka && n)
{
if(ka%10 != n%10)
return 0;
ka/=10;
n/=10;
}
if(n == 0)
return 1;
else
return 0;
}

ll Ten(int wei)
{
ll res = 1;
for(int i=0;i<wei;i++)
res *= 10;
return res;
}

ll toTen(ll tmp)
{
ll res = 1;
while(tmp)
{
res *= 10;
tmp /= 10;
}
return res;
}

ll ans;
int w[12],ind;

void BFS(ll n)
{
queue<ll> que;
ll m,x,y;
for(y=0;y<=9;y++)
{
ll ka = y*y;
if(ka%10 == w[1])
{
if(Scheck(ka,n))
{
if(y < ans)
ans = y;
}
else
que.push(y);
}
}
int layer = 1;
while(!que.empty())
{
layer++;
if(layer > 10 || layer >= ind)
return;
ll ten = Ten(layer-1);
int qsize = que.size();
while(qsize--)
{
ll tmp = que.front();
que.pop();
for(x=0;x<=9;x++)
{
m = ten*x+tmp;
ll m2 = m*m;
if((m2/ten)%10 == w[layer])
{
if(Scheck(m2,n))
{
if(m < ans)
ans = m;
}
else
que.push(m);
}
}
}
}
return;
}

int main()
{
int T;
ll n;
scanf("%d",&T);
while(T--)
{
scanf("%lld",&n);
if(n == 0)
{
printf("0\n");
continue;
}
ll kn = n;
ind = 1;
while(kn)
{
w[ind++] = kn%10;
kn/=10;
}
ans = Mod;
BFS(n);
if(ans == Mod)
puts("None");
else
printf("%lld\n",ans);
}
return 0;
}
View Code

C.贪吃蛇

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define Mod 1000000007
#define ll long long
using namespace std;
#define N 107

struct Point
{
int x,y;
}p[11];

struct node
{
int x,y;
int num,step;
}S;

char mp[17][17];
int vis[70000][16][16];
int R,C,K;
int EX,EY;
int dx[4] = {1,0,0,-1};
int dy[4] = {0,1,-1,0};

int p_to_num(Point *p)
{
int i,k;
int res = 0,now = 0;
for(i=1;i<K;i++)
{
int sx = p[i].x;
int sy = p[i].y;
int tx = p[i+1].x;
int ty = p[i+1].y;
if(sx > tx && sy == ty)
k = 3;   //下
else if(sx == tx && sy > ty)
k = 2;   //右
else if(sx < tx && sy == ty)
k = 0;   //上
else if(sx == tx && sy < ty)
k = 1;   //左
k <<= now;
now += 2;
res |= k;
}
return res;
}

bool OK(int nx,int ny)
{
if(nx >= 0 && nx < R && ny >= 0 && ny < C)
return true;
return false;
}

bool check(int num)
{
int i,j,k;
k = K-1;
int x = 0,y = 0;
while(k--)
{
x += dx[num&3];
y += dy[num&3];
if(x == 0 && y == 0)
return false;
num >>= 2;
}
return true;
}

int BFS(node S)
{
int i,j,k;
queue<node> que;
memset(vis,0,sizeof(vis));
que.push(S);
vis[S.num][S.x][S.y] = 1;
int MOD = (1<<((K-1)*2));
while(!que.empty())
{
node tmp = que.front();
que.pop();
if(tmp.x == EX && tmp.y == EY)
return tmp.step;
for(i=0;i<4;i++)
{
if(K <= 1 || ((tmp.num&3) != i))
{
int nx = tmp.x + dx[i];
int ny = tmp.y + dy[i];
if(!OK(nx,ny) || mp[nx][ny] == '#')
continue;
node now;
now.num = (tmp.num << 2);
now.num |= (3-i);
now.num %= MOD;
if(vis[now.num][nx][ny])   //状态已走过
continue;
if(!check(now.num))    //咬到蛇身
continue;
vis[now.num][nx][ny] = 1;
now.x = nx;
now.y = ny;
now.step = tmp.step + 1;
que.push(now);
}
}
}
return -1;
}

int main()
{
int i,j,k,cs = 1;
while(scanf("%d%d",&R,&C)!=EOF)
{
K = 1;
for(i=0;i<R;i++)
{
scanf("%s",mp[i]);
for(j=0;j<C;j++)
{
if(mp[i][j] == '@')
EX = i,EY = j;
if(mp[i][j] >= '1' && mp[i][j] <= '9')
{
k = mp[i][j] - '0';
p[k].x = i,p[k].y = j;
K = max(K,k);
}
}
}
S.num = p_to_num(p);
S.x = p[1].x;
S.y = p[1].y;
S.step = 0;
printf("Case #%d: %d\n",cs++,BFS(S));
}
return 0;
}
View Code

D.方老师与素数

BFS搜索。每次改变一位（千位，百位，十位或个位），拓展状态，直到达到目标状态。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <queue>
#define Mod 1000000007
using namespace std;
#define N 10007

int u[N],c,vis[N],prime[N];
int n,a,b,flag;
struct node
{
int num,step;
}S,E;

void doit()
{
int i,j;
c=0;
for(i=2;i<=10003;i++)
u[i] = 1;
for(i=2;i<=10003;i++)
{
if(u[i])
prime[c++] = i;
for(j=0;j<c&&i*prime[j]<=10003;j++)
{
u[i*prime[j]] = 0;
if(i%prime[j] == 0)
break;
}
}
}

int change(int base,int num,int ind)
{
char ss[5];
ss[0] = base/1000 + 48;
ss[1] = (base/100)%10 + 48;
ss[2] = (base/10)%10 + 48;
ss[3] = base%10 + 48;
ss[ind] = num + 48;
ss[4] = '\0';
return atoi(ss);
}

int bfs(node S,int b)
{
queue<node> que;
node k;
while(!que.empty())
que.pop();
int i,j,res = 0;
int ka = 1;
flag = 0;
memset(vis,0,sizeof(vis));
que.push(S);
vis[S.num] = 1;
while(!que.empty())
{
node tmp = que.front();
que.pop();
if(tmp.num == b)
{
flag = 1;
return tmp.step;
}
for(i=1;i<=9;i++)  //千位
{
int now = change(tmp.num,i,0);
if(now != tmp.num && u[now] && !vis[now])
{
vis[now] = 1;
k.num = now;
k.step = tmp.step + 1;
que.push(k);
}
}
for(i=1;i<=3;i++)   //百,十,个位
{
for(j=0;j<=9;j++)
{
int now = change(tmp.num,j,i);  //i位变为j
if(now != tmp.num && u[now] && !vis[now])
{
vis[now] = 1;
k.num = now;
k.step = tmp.step + 1;
que.push(k);
}
}
}
}
return res;
}

int main()
{
int t,i,a,b;
doit();
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&a,&b);
S.num = a;
S.step = 0;
int res = bfs(S,b);
if(!flag)
puts("Impossible");
else
printf("%d\n",res);
}
return 0;
}
View Code

E.Sticks

DFS+剪枝

ind:当前枚举到第ind根棒子

left:要组成LEN还需left长度

remain:剩下的总长度为remain

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 107

int a[N],vis[N];
int S,LEN,n;

int DFS(int ind,int left,int remain)  //当前枚举到第ind根棒子，要组成LEN还需left长度，剩下的总长度为remain
{
int i;
if(remain == LEN)
return 1;
for(i=ind;i<n;i++)
{
if(!vis[i] && a[i] <= left)
{
vis[i] = 1;   //用这根棒子
if(a[i] < left && DFS(i+1,left-a[i],remain-a[i]))
return 1;
else if(a[i] == left && DFS(0,LEN,remain-a[i]))
return 1;
vis[i] = 0;   //都没成功，这根不能用
if(remain == S || a[i] == left || left == LEN) //如果一根都没用，肯定找不到了，如果不能找到一根长度为LEN的木棍，以后也不能找到了，如果这根木棍长度等于剩下的，但是DFS没成功，说明不可能找到一根或多根将其凑齐了
return 0;
while(i+1 < n && a[i] == a[i+1])  //相同的木棍，不成功就都不成功
i++;
}
}
return 0;
}

int cmp(int ka,int kb)
{
return ka > kb;
}

int main()
{
while(scanf("%d",&n)!=EOF && n)
{
S = 0;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
S += a[i];
}
sort(a,a+n,cmp);
for(LEN=a[0];LEN<=S;LEN++)
{
if(S%LEN == 0)
{
memset(vis,0,sizeof(vis));
if(DFS(0,LEN,S))
{
printf("%d\n",LEN);
break;
}
}
}
}
return 0;
}
View Code

F.方老师与迷宫

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

char mp[32][32][32];
char ss[32];
int vis[32][32][32];

struct node
{
int x,y,z;
int step;
}Sa,Ea;

int sx[7] = {1,-1,0,0,0,0};
int sy[7] = {0,0,1,-1,0,0};
int sz[7] = {0,0,0,0,1,-1};
int L,R,C;

bool OK(int nx,int ny,int nz)
{
if(nx >= 0 && nx < R && ny >= 0 && ny < C && nz >= 0 && nz < L)
return true;
return false;
}

int bfs(node S,node E)
{
queue<node> que;
while(!que.empty())
que.pop();
que.push(S);
memset(vis,0,sizeof(vis));
vis[S.x][S.y][S.z] = 1;
while(!que.empty())
{
node tmp = que.front();
que.pop();
if(tmp.x == E.x && tmp.y == E.y && tmp.z == E.z)
return tmp.step;
for(int i=0;i<6;i++)
{
node now;
now.x = tmp.x + sx[i];
now.y = tmp.y + sy[i];
now.z = tmp.z + sz[i];
if(!OK(now.x,now.y,now.z) || mp[now.z][now.x][now.y] == '#' || vis[now.x][now.y][now.z])
continue;
now.step = tmp.step + 1;
vis[now.x][now.y][now.z] = 1;
que.push(now);
}
}
return -1;
}

int main()
{
int i,j,k;
while(scanf("%d%d%d",&L,&R,&C)!=EOF && (L&&R&&C))
{
for(i=0;i<L;i++)
{
for(j=0;j<R;j++)
{
scanf("%s",mp[i][j]);
for(k=0;k<C;k++)
{
if(mp[i][j][k] == 'S')
Sa.x = j,Sa.y = k,Sa.z = i,Sa.step = 0;
else if(mp[i][j][k] == 'E')
Ea.x = j,Ea.y = k,Ea.z = i,Ea.step = Mod;
}
}
getchar();
}
//printf("%d %d %d\n%d %d %d\n",S.x,S.y,S.z,E.x,E.y,E.z);
int res = bfs(Sa,Ea);
if(res != -1)
printf("Escaped in %d minute(s).\n",res);
else
puts("Trapped!");
}
return 0;
}
View Code

G.Eight Puzzle

Cantor展开（康托展开）可以求一个排列在所有这几个数的排列中的位置:

a(i)为i右边的比a(i)小的数的个数。

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

struct node
{
int puzzle[3][3];
int step;
};

int hash[N],vis[N];
int a[10],b[3][3];
char ss[30];
int mp[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
int sx[4] = {1,0,-1,0};
int sy[4] = {0,1,0,-1};
int fact[11] = {0,1,2,6,24,120,720,5040,40320,362880,3628800};

int Cantor(int *a)   //康托展开
{
int i,j,cnt;
int res = 0;
for(i=0;i<9;i++)
{
cnt = 0;
for(j=i+1;j<9;j++)
if(a[i] > a[j])
cnt++;
res += cnt*fact[9-i-1];
}
return res;
}

void DB_to_SG(int *a,int b[3][3])  //二维转一维
{
int i,j,k = 0;
for(int i=0;i<3;i++)
for(j=0;j<3;j++)
a[k++] = b[i][j];
}

int HS(int b[3][3])   //取得排列的Cantor展开的值
{
int i,j,k,res;
DB_to_SG(a,b);
return Cantor(a);
}

bool OK(int nx,int ny)
{
if(nx >= 0 && nx < 3 && ny >= 0 && ny < 3)
return true;
return false;
}

int copyDB(int (*a)[3],int (*b)[3])  //复制数组
{
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
a[i][j] = b[i][j];
}

void BFS()
{
queue<node> que;
while(!que.empty())
que.pop();
int i,j,k;
int nx,ny;
node S;
copyDB(S.puzzle,mp);
copyDB(b,S.puzzle);
int hsb = HS(b);
vis[hsb] = 1;
hash[hsb] = 0;
S.step = 0;
que.push(S);
while(!que.empty())
{
node tmp = que.front();
que.pop();
for(i=0;i<3;i++)
for(j=0;j<3;j++)
{
b[i][j] = tmp.puzzle[i][j];
if(b[i][j] == 9)
nx = i,ny = j;
}
for(k=0;k<4;k++)
{
int kx = nx + sx[k];
int ky = ny + sy[k];
if(!OK(kx,ky))
continue;
swap(b[nx][ny],b[kx][ky]);
int hsb = HS(b);   //Cantor展开值作为状态
node now;
if(!vis[hsb])
{
copyDB(now.puzzle,b);
vis[hsb] = 1;
hash[hsb] = tmp.step + 1;
now.step = tmp.step + 1;
que.push(now);
}
swap(b[nx][ny],b[kx][ky]);
}
}
}

int main()
{
memset(hash,0,sizeof(hash));
memset(vis,0,sizeof(vis));
BFS();
while(gets(ss))
{
int i,j,k = 0;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
{
if(ss[k] == 'x')
b[i][j] = 9;
else
b[i][j] = ss[k] - '0';
k += 2;
}
int hsb = HS(b);
if(!hsb || (hsb && hash[hsb]))
cout<<hash[hsb]<<endl;
else
puts("unsolvable");
}
return 0;
}
View Code

H.一个简单的走迷宫问题

1.向左转

2.向右转

3.向后转  （step = 2）

4.向此时的方向走1步

5.向此时的方向走2步

6.向此时的方向走3步

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

int mp[55][55],nmp[55][55],flag[4],dis[4][55][55];
int R,C;

struct node
{
int x,y;
int dr;
int step;
bool operator<(const node &a)const
{
return step > a.step;
}
}S,E;

bool OK(int nx,int ny)
{
if(nx >= 0 && nx < R-1 && ny >= 0 && ny < C-1)
return true;
return false;
}

int bfs(node S,node E)
{
priority_queue<node> que;
while(!que.empty())
que.pop();
que.push(S);
dis[S.dr][S.x][S.y] = 0;
while(!que.empty())
{
node tmp = que.top();
que.pop();
if(tmp.x == E.x && tmp.y == E.y)
return tmp.step;
memset(flag,0,sizeof(flag));
for(int i=2;i<=7;i++) //走的步数
{
if(i <= 4)
{
node now;
now.x = tmp.x;
now.y = tmp.y;
if(i == 2)   //向右转然后走
{
now.step = tmp.step + 1;
now.dr = (tmp.dr + 1)%4;
}
else if(i == 3)  //向左转然后走
{
now.step = tmp.step + 1;
now.dr = (tmp.dr + 3)%4;
}
else if(i == 4)  //向后转然后走
{
now.step = tmp.step + 2;
now.dr = (tmp.dr + 2)%4;
}
if(dis[now.dr][now.x][now.y] != -1 && now.step >= dis[now.dr][now.x][now.y])
continue;
dis[now.dr][now.x][now.y] = now.step;
que.push(now);
}
else
{
node next;
if(tmp.dr == 0)  //UP
{
next.x = tmp.x - i + 4;
next.y = tmp.y;
}
else if(tmp.dr == 1)  //RIGHT
{
next.x = tmp.x;
next.y = tmp.y + i - 4;
}
else if(tmp.dr == 2)  //DOWN
{
next.x = tmp.x + i - 4;
next.y = tmp.y;
}
else if(tmp.dr == 3) //LEFT
{
next.x = tmp.x;
next.y = tmp.y - i + 4;
}
if(!OK(next.x,next.y) || nmp[next.x][next.y] == 1)
break;
next.step = tmp.step + 1;  //
next.dr = tmp.dr;
if(dis[next.dr][next.x][next.y] != -1 && next.step >= dis[next.dr][next.x][next.y])
continue;
dis[next.dr][next.x][next.y] = next.step;
que.push(next);
}
}
}
return -1;
}

int main()
{
int i,j;
while(scanf("%d%d",&R,&C)!=EOF && R && C)
{
memset(nmp,0,sizeof(nmp));
for(i=0;i<R;i++)
{
for(j=0;j<C;j++)
{
scanf("%d",&mp[i][j]);
if(mp[i][j] == 1)
{
nmp[i][j] = 1;
if(j>=1)
{
nmp[i][j-1] = 1;
if(i>=1)
nmp[i-1][j-1] = 1;
}
if(i>=1)
{
nmp[i-1][j] = 1;
if(j>=1)
nmp[i-1][j-1] = 1;
}
}
}
}
memset(dis,-1,sizeof(dis));
scanf("%d%d%d%d%d",&S.x,&S.y,&E.x,&E.y,&S.dr);
S.x--,S.y--,E.x--,E.y--;
S.step = 0;
E.dr = 0,E.step = Mod;
int res = bfs(S,E);
printf("%d\n",res);
}
return 0;
}
View Code

I.分割包围

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define Mod 1000000007
using namespace std;
#define N 50007

int d[N];
int x,n,m;

bool check(int mid)
{
int i,j;
int cnt = 0;
for(i=0;i<=n+1;i++)
{
for(j=i+1;j<=n+1;j++)
{
if(d[j]-d[i] < mid && j <= n)  //如果两个间隔小于mid，则要增大，即抹除j的这个
cnt++;
else if(d[j]-d[i] < mid && j == n+1)
{
cnt++;
i = Mod;
}
else
{
i = j-1;
break;
}
}
}
if(cnt <= m)
return true;
return false;
}

int main()
{
int i,j;
scanf("%d%d%d",&x,&n,&m);
for(i=1;i<=n;i++)
scanf("%d",&d[i]);
sort(d+1,d+n+1);
d[0] = 0;
d[n+1] = x;
int mini = Mod;
for(i=1;i<=n+1;i++)
{
if(d[i]-d[i-1] < mini)
mini = d[i]-d[i-1];
}
int low = mini;
int high = x;
while(low < high)
{
int mid = (low+high+1)/2;
if(check(mid))
low = mid;
else
high = mid-1;
}
printf("%d\n",low);
return 0;
}
View Code

J.魔法少女小蟹

dis表示到当前状态的步数（最小）。

BFS出来后，枚举6位数的每一位和指针位置和10种状态，看此状态是否已访问，如果已访问，表示能够到达这个状态，然后看从这个状态到目标状态还需多少步（有可能达不到），然后看dis[状态]+步数是否小于最小步数，是则更新答案。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define Mod 1000000007
#define INT 2147483647
using namespace std;
#define N 50007

struct node
{
int p[7];
int point,state;
int step;
}S;

void Popy(int *p1,int *p2)
{
for(int i=1;i<7;i++)
p1[i] = p2[i];
}

int dis[7][7][7][7][7][7][7][10];
int E[7],SS[7];

int min(int ka,int kb)
{
if(ka < kb)
return ka;
return kb;
}

int max(int ka,int kb)
{
if(ka > kb)
return ka;
return kb;
}

void BFS(node S)
{
queue<node> que;
memset(dis,-1,sizeof(dis));
que.push(S);
dis[S.p[1]][S.p[2]][S.p[3]][S.p[4]][S.p[5]][S.p[6]][1][0] = 0;
while(!que.empty())
{
node tmp = que.front();
que.pop();
for(int i=0;i<4;i++)
{
node now;
if(i == 0)   //与左边交换
{
swap(tmp.p[1],tmp.p[tmp.point]);
Popy(now.p,tmp.p);
swap(tmp.p[1],tmp.p[tmp.point]);
now.point = tmp.point;
now.state = tmp.state;
now.step = tmp.step + 1;
if(dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state] == -1 || (dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state] != -1 && now.step < dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state]))
{
dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state] = now.step;
que.push(now);
}
}
else if(i == 1)   //与右边交换
{
swap(tmp.p[6],tmp.p[tmp.point]);
Popy(now.p,tmp.p);
swap(tmp.p[6],tmp.p[tmp.point]);
now.point = tmp.point;
if(tmp.state <= 3)
now.state = tmp.state + 6;
else if(tmp.state == 4)
now.state = tmp.state + 1;
else
now.state = tmp.state;
now.step = tmp.step + 1;
if(dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state] == -1 || (dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state] != -1 && now.step < dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state]))
{
dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state] = now.step;
que.push(now);
}
}
else if(i == 2)   //左移
{
Popy(now.p,tmp.p);
now.point = max(1,tmp.point-1);
now.state = tmp.state;
now.step = tmp.step + 1;
if(dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state] == -1 || (dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state] != -1 && now.step < dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state]))
{
dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state] = now.step;
que.push(now);
}
}
else if(i == 3)  //右移
{
Popy(now.p,tmp.p);
now.point = min(6,tmp.point+1);
if(tmp.state < 5)
now.state = tmp.state+1;
else if(tmp.state == 5)
now.state = tmp.state;
else if(tmp.state < 9)
now.state = tmp.state+1;
else
now.state = tmp.state-4;
now.step = tmp.step + 1;
if(dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state] == -1 || (dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state] != -1 && now.step < dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state]))
{
dis[now.p[1]][now.p[2]][now.p[3]][now.p[4]][now.p[5]][now.p[6]][now.point][now.state] = now.step;
que.push(now);
}
}
}
}
}

int main()
{
int a,b,i;
int h[7];
int pot,status;
while(scanf("%d%d",&a,&b)!=EOF)
{
S.p[1] = 1;   //标号。初始都在自己的位置
S.p[2] = 2;
S.p[3] = 3;
S.p[4] = 4;
S.p[5] = 5;
S.p[6] = 6;
S.point = 1;
S.state = 0;
S.step = 0;
SS[1] = (a/100000)%10;
SS[2] = (a/10000)%10;
SS[3] = (a/1000)%10;
SS[4] = (a/100)%10;
SS[5] = (a/10)%10;
SS[6] = a%10;
E[1] = (b/100000)%10;
E[2] = (b/10000)%10;
E[3] = (b/1000)%10;
E[4] = (b/100)%10;
E[5] = (b/10)%10;
E[6] = b%10;
BFS(S);
int ans = Mod;
for(h[1]=1;h[1]<=6;h[1]++)
{
for(h[2]=1;h[2]<=6;h[2]++)
{
if(h[2] != h[1])
{
for(h[3]=1;h[3]<=6;h[3]++)
{
if(h[3] != h[2] && h[3] != h[1])
{
for(h[4]=1;h[4]<=6;h[4]++)
{
if(h[4] != h[1] && h[4] != h[2] && h[4] != h[3])
{
for(h[5]=1;h[5]<=6;h[5]++)
{
if(h[5] != h[1] && h[5] != h[2] && h[5] != h[3] && h[5] != h[4])
{
for(h[6]=1;h[6]<=6;h[6]++)
{
if(h[6] != h[1] && h[6] != h[2] && h[6] != h[3] && h[6] != h[4] && h[6] != h[5])
{
for(pot=1;pot<=6;pot++)
{
for(status=0;status<10;status++)
{
if(dis[h[1]][h[2]][h[3]][h[4]][h[5]][h[6]][pot][status] != -1)
{
int cnt = 0;
int t,r;
int flag = 1;                      //No.  status
if(status <= 5)                    //1    1
{                                  //2    12
for(t=1;t<=status+1;t++)       //3    123
cnt += abs(E[t]-SS[h[t]]); //4    1234
for(t;t<=6;t++)                //5    12345
if(E[t] != SS[h[t]])       //6    123456
{                          //7    16
flag = 0;              //8    126
break;                 //9    1236
}                          //10   12346
if(!flag)
continue;
}
else if(status >= 6 && status <= 9)
{
for(r=1;r<=status-5;r++)
cnt += abs(E[r]-SS[h[r]]);
for(r;r<6;r++)
if(E[r] != SS[h[r]])
{
flag = 0;
break;
}
if(!flag)
continue;
cnt += abs(E[6]-SS[h[6]]);
}
ans = min(ans,dis[h[1]][h[2]][h[3]][h[4]][h[5]][h[6]][pot][status]+cnt);
}
}
}
}
}
}
}
}
}
}
}
}
}
}
printf("%d\n",ans);
}
return 0;
}
View Code

K.Can You Help God Wu

BFS，枚举涂法，用每个位置用0表示染上了错误的颜色，1表示染上了正确的颜色，用一个十进制数表示，最大不超过2^16.

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

struct node
{
int num,step;
}S;

char E[3][18];
int vis[70000];
int n,C;

int BFS(node S)
{
queue<node> que;
que.push(S);
vis[S.num] = 1;
int D = ((1<<(2*n))-1);
while(!que.empty())
{
node tmp = que.front();
que.pop();
if(tmp.num == D)
return tmp.step;
int i,j,a,b;
for(i=0;i<2;i++)
{
for(j=0;j<n;j++)
{
int pos = i*n+j;
node now;
if(tmp.num & (1<<pos)) //已经是该颜色
continue;
int Num = 0;
for(a=pos;a<(i==0?n:2*n);a++)  //往右
{
if(tmp.num & (1<<a))   //已经染好，不能再涂
break;
if(E[a/n][a%n] == E[pos/n][pos%n])
Num = Num | (1<<a);    //染色
}
for(a=pos-1;a>=(i==0?0:n);a--)  //往左
{
if(tmp.num & (1<<a))
break;
if(E[a/n][a%n] == E[pos/n][pos%n])
Num = Num | (1<<a);
}
for(pos=Num;pos!=0;pos=Num&(pos-1))  //子状态
{
if(vis[tmp.num|pos])
break;
vis[tmp.num|pos] = 1;
now.num = tmp.num|pos;
now.step = tmp.step + 1;
que.push(now);
}
pos = i*n+j;
if(i >= 1)
continue;
if(tmp.num & (1<<(n+pos)))
continue;
Num = 0;
for(a=pos;a<n;a++)  //双行往右
{
if(tmp.num & (1<<a) || tmp.num & (1<<(a+n)))
break;
if(E[a/n][a%n] == E[pos/n][pos%n])
Num = Num | (1<<a);
if(E[(a+n)/n][(a+n)%n] == E[pos/n][pos%n])
Num = Num | (1<<(a+n));
}
for(a=pos-1;a>=0;a--)  //双行往左
{
if(tmp.num & (1<<a) || tmp.num & (1<<(a+n)))
break;
if(E[a/n][a%n] == E[pos/n][pos%n])
Num = Num | (1<<a);
if(E[(a+n)/n][(a+n)%n] == E[pos/n][pos%n])
Num = Num | (1<<(a+n));
}
for(pos=Num;pos!=0;pos=Num&(pos-1))  //子状态
{
if(vis[tmp.num|pos])
continue;
vis[tmp.num|pos] = 1;
now.num = tmp.num|pos;
now.step = tmp.step + 1;
que.push(now);
}
}
}
}
}

int main()
{
int t,cs = 1,i,j;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(i=0;i<=1;i++)
scanf("%s",E[i]);
memset(vis,0,sizeof(vis));
S.num = 0;
S.step = 0;
int res = BFS(S);
printf("Case #%d: %d\n",cs++,res);
}
return 0;
}
View Code

L.STAMPS

DFS

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

struct node
{
int deno[5];
int num;
}E,tmp;

int stamp[N];
int vis[N];
int n,m,S;
int isTie,flag;

int Totaltype(node ka)   //计算这个组合的种类数
{
memset(vis,0,sizeof(vis));
int res = 0;
for(int i=0;i<ka.num;i++)
if(!vis[ka.deno[i]])
res++,vis[ka.deno[i]] = 1;
return res;
}

int Max(node ka)   //找出票面价值的最大值
{
int maxi = -Mod;
for(int i=0;i<ka.num;i++)
if(maxi < stamp[ka.deno[i]])
maxi = stamp[ka.deno[i]];
return maxi;
}

int copyAN(int *a,int *b,int num)  //复制结果
{
for(int i=0;i<num;i++)
a[i] = b[i];
}

void check(node &ka,node &kb)  //比较函数
{
int typa = Totaltype(ka);
int typb = Totaltype(kb);
int maxa = Max(ka);
int maxb = Max(kb);

if(ka.num == -Mod || (typa < typb) || (typa == typb && ka.num > kb.num) || (typa == typb && ka.num == kb.num && maxa < maxb))
{
copyAN(ka.deno,kb.deno,kb.num);
ka.num = kb.num;
isTie = 0;
return;
}
if(typa == typb && ka.num == kb.num && maxa == maxb)
isTie = 1;
}

void DFS(int sum,int step)   //sum:当前组合的和  step:当前已经用到了第几种邮票
{
if(sum == S)
{
flag = 1;
check(E,tmp);
return;
}

if(sum > S || tmp.num >= 4)
return;
for(int k=step;k<n;k++)    //可用多次，所以从上次结束的位置开始枚举
{
tmp.deno[tmp.num] = k;
tmp.num++;
DFS(sum+stamp[k],k);
tmp.num--;
}
}

int main()
{
int x,y,i,j;
while(scanf("%d",&x)!=EOF && x)
{
n = 0;
stamp[0] = x;
while(stamp[n])
{
n++;
scanf("%d",&stamp[n]);
}                           //stamp[n] = 0
sort(stamp,stamp+n);
while(scanf("%d",&S)!=EOF && S)
{
printf("%d ",S);
memset(E.deno,0,sizeof(E.deno));
E.num = -Mod;
memset(tmp.deno,0,sizeof(tmp.deno));
tmp.num = 0;
flag = isTie = 0;
DFS(0,0);
if(!flag)
puts("---- none");
else
{
sort(E.deno,E.deno+E.num);
printf("(%d):",Totaltype(E));
if(isTie)
puts(" tie");
else
{
for(i=0;i<E.num;i++)
printf(" %d",stamp[E.deno[i]]);
printf("\n");
}
}
}
}
return 0;
}
View Code

(2014.5.17 0:34)

posted @ 2014-05-14 19:52 whatbeg 阅读(...) 评论(...) 编辑 收藏