您的位置:首页 > 其它

codevs 3290 noip 2013 Day2 T3华容道

2016-11-06 16:16 344 查看
唔马上要考noip了 泪目。希望rp++。

莫名被archer圈粉。

今天终于搞定这道题了 呼。。。

所以orz当年4(+3)神犇。

题目描述 Description

小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间。

小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:

在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的;

有些棋子是固定的,有些棋子则是可以移动的;

任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。 游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。

给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的,但是棋盘上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次玩的时候,空白的格子在第 EX_i 行第 EY_i 列,指定的可移动棋子的初始位置为第 SX_i 行第 SY_i 列,目标位置为第 TX_i 行第 TY_i 列。

假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。

输入描述 Input Description

第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n、m 和 q;

接下来的 n 行描述一个 n*m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,0 表示该格子上的棋子是固定的,1 表示该格子上的棋子可以移动或者该格子是空白的。

接下来的 q 行,每行包含 6 个整数依次是 EX_i、EY_i、SX_i、SY_i、TX_i、TY_i,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。

输出描述 Output Description

输出有 q 行,每行包含 1 个整数,表示每次游戏所需要的最少时间,如果某次游戏无法完成目标则输出-1。

样例输入 Sample Input

3 4 2

0 1 1 1

0 1 1 0

0 1 0 0

3 2 1 2 2 2

1 2 2 2 3 2

样例输出 Sample Output

2

-1

对于 30%的数据,1 ≤ n, m ≤ 10,q = 1;

对于 60%的数据,1 ≤ n, m ≤ 30,q ≤ 10;

对于 100%的数据,1 ≤ n, m ≤ 30,q ≤ 500。

60%很好说吧。bfs就可以。。直接上代码了!【得了65 是要闹哪样】

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
//by mars_ch
using namespace std;
struct data
{
int x,y;
int kx,ky;
int dis;
}a;
int n,m,k;
int ex,ey,sx,sy,tx,ty;
int map[30][30];
int vis[30][30][30][30];
int dx[5]={1,-1,0,0};
int dy[5]={0,0,1,-1};
queue<data> q;
void bfs()
{
while(!q.empty()) q.pop();
memset(vis,0,sizeof(vis));
data t;
t.x=sx,t.y=sy;
t.kx=tx,t.ky=ty;
t.dis=0;
if(t.x == ex && t.y==ey){
printf("0\n");
return;
}
vis[sx][sy][tx][ty]=1;
q.push(t);
while(!q.empty())
{
data v=q.front();
q.pop();

for(int i=0;i<4;i++)
{
int nx=v.x,ny=v.y;
int bx=v.kx+dx[i],by=v.ky+dy[i];;
if(bx == nx && by == ny)
{
nx=v.kx,ny=v.ky;
}
if(nx<=n && ny<=m && nx>0 && ny>0 && bx<=n && bx>0 && by<=m && by>0 && map[nx][ny]==1 && map[bx][by] == 1 &&!vis[nx][ny][bx][by])
{
vis[nx][ny][bx][by]=1;
data u;
u.x=nx,u.y=ny,u.kx=bx,u.ky=by;
u.dis=v.dis+1;
if(nx == ex && ny == ey)
{
printf("%d\n",u.dis);
return;
}
q.push(u);
}
}
}
printf("-1\n");
return;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&map[i][j]);
}
}
while(k--)
{
scanf("%d%d%d%d%d%d",&tx,&ty,&sx,&sy,&ex,&ey);
bfs();
}
return 0;
}


然后来说正解:

好吧,又看了正解yy了很久。

然后网上的代码都好繁琐啊 泪目。。

所以 根据60分算法观察,我们搜索到了许多并不会移动的状态。并且每次询问的 棋盘式固定的也就是可移动的棋子是固定的。

我们又拥有2种操作:

1.将空白格子移至目标棋子想要前进的方向。

2.空白格子和目标棋子相邻,交换【一起移动】

对于每个合法点A(x,y),枚举一个E(ex,ey)表示相邻的空格的位置,和一个T(tx,ty)表示要把目标棋子从这个格子移向的位置【方向】。



所以如果将所有的状态都处理出来,那么每个格子到每个格子就先定了。

所以 我们只需要建边跑一边spfa就OK了!

注意状态时3维的啦~

上代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define inf 1000000007
//by mars_ch
using namespace std;
int n,m,k;
int ex,ey,sx,sy,tx,ty;
int map[35][35],ha[32][35][5],dis[35][35],d[5005],inq[5005];
int dx[5]={1,-1,0,0};
int dy[5]={0,0,1,-1};
struct data
{
int f,t,w,nxt;
}e[300005];
int first[100005],tot;
void add(int a,int b,int c)
{
e[tot].f=a,e[tot].t=b,e[tot].w=c;
e[tot].nxt=first[a],first[a]=tot++;
}
int bfs(int stx,int sty,int edx,int edy)
{
if(stx == edx && sty == edy) return 0;
queue<pair<int,int> > q;
memset(dis,-1,sizeof(dis));
q.push(make_pair(stx,sty));
dis[stx][sty]=0;
while(!q.empty())
{
int nx=q.front().first,ny=q.front().second;
q.pop();
for(int i=0;i<4;i++){
int xx=nx+dx[i],yy=ny+dy[i];
if(!map[xx][yy] || dis[xx][yy]!=-1)continue;
dis[xx][yy]=dis[nx][ny]+1;
if(xx == edx && yy==edy){
return dis[xx][yy];
}
q.push(make_pair(xx,yy));
}
}
return inf;
}
void pre_bfs(int x,int y)
{
for(int i=0;i<4;i++){
int nx=x+dx[i],ny=y+dy[i];
if(!map[nx][ny]) continue;
for(int j=0;j<4;j++){
int xx=x+dx[j],yy=y+dy[j];
if(!map[xx][yy]) continue;
int temp=bfs(nx,ny,xx,yy);
if(temp!=inf){
add(ha[x][y][i],ha[xx][yy][j^1],temp+1);
}
}
}
}
int spfa(int s,int t)
{
queue<int> q;
for(int i=1;i<=t;i++)
{
d[i]=inf;
inq[i]=0;
}
d[s]=0;
q.push(s);
inq[s]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
inq[u]=0;

for(int i=first[u];i!=-1;i=e[i].nxt)
{
int t=e[i].t;
if(d[t]>d[u]+e[i].w){
d[t]=d[u]+e[i].w;
if(!inq[t]){
inq[t]=1;
q.push(t);
}
}
}
}
if(d[t] == inf) return -1;
else return d[t];

}
int main()
{
int h=0;
scanf("%d%d%d",&n,&m,&k);
memset(first,-1,sizeof(first));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&map[i][j]);
for(int d=0;d<4;d++)
{
ha[i][j][d]=++h;
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(map[i][j]){
map[i][j]=0;
pre_bfs(i,j);
map[i][j]=1;
}
}
}
while(k--)
{
scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
if(sx == tx && sy==ty){
puts("0");
continue;
}
int S=++h,T=++h;
map[sx][sy]=0;
for(int i=0;i<4;i++)
{
int nx=sx+dx[i],ny=sy+dy[i];
if(!map[nx][ny]) continue;
int temp=bfs(ex,ey,nx,ny);
if(temp!=inf){
add(S,ha[sx][sy][i],temp);
}
}
map[sx][sy]=1;

for(int i=0;i<4;i++)
{
int nx=tx+dx[i],ny=ty+dy[i];
if(map[nx][ny]){
add(ha[tx][ty][i],T,0);
}
}
printf("%d\n",spfa(S,T));

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: