洛谷P 1979華容道題解
8407 ワード
ピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピューピュー
洛谷P 1979華容道題解
NOIP 2018まであと7日で問題解を書いて人柄を蓄える
(初めて紫問題の問題解を書いたのはまだ少し興奮している)
いくつかの説明
1、本題解とコード中の0/1/2/3はそれぞれ上/下/左/右を表す
2、明確な表現のために、問題解には目標駒(タイトルの中の(SX,SY)が(B)、目標格子(タイトルの中の(TX,TY)が)(C)、空白格子が(E)
【考え方分析】何人かのdalaoが言ったように、この問題の建図は実行可能な状態をエッジにつなぎ、質問するたびに最短ルートを走ることである.
私が$ok[i][j][0/1/2/3]$で(B)が点((i,j))にある場合、4方向に空き格子がある可能性があるかどうか(各グループのクエリで空き格子が到達できるかどうかは考慮せず、その格子が固定格子であるかどうか、または境界を越えているかどうかのみを考慮する.)
このセクションのコードは次のとおりです.
judge関数は、空白または境界であるかどうかを判断するために使用されます.
図面を作成するために、私は状態を1次元配列に保存します:格子の番号:上から下へ左から右へ編みます
\(e.g.\) 1 2 3 4 5 6 7 8 ……
ステータスの番号(e.g.)
1番グリッドの4つのステータス番号は0123です.
すると、次の番号付け関数が得られます.
(q)グループが尋ねる地図の状況は同じなので、先に図を建てることができます.
どのような2つの状態がエッジをつなぐことができますか?
2つの状況を考慮します.
・空白の格子が(B)を上下左右にぐるぐる回っている
bfsで乱転が少なくとも何回上から下へ、左から右へ...
注意が必要なのは、乱転時(B)は動けません!!!(ここは長い間QQQQをしていました)
・空白格子と(B)交換位置
両方のステータスが存在することを保証する必要があります.
距離1の辺をつなげてください.
駒が動かず、空白格が乱転する場合:
qwq
これで初期化が完了しました!(プラスエッジの操作は普通の図論と同じw)
各グループの質問について、まず特審します.
そして、最初の状態をどのように図に移すかを考えます.
空白格が(B)に隣接する状況しか存在しないので、so暴力は空白格を(B)の4つの方向に走らせようと試みるとよい
そして、楽しくSPFAを走ります
最後に、到着できるかどうかを楽しくチェックします(C)
アノテーションコードQWQを貼る
终わって花を撒きます!!!
by Erutsiom
転載先:https://www.cnblogs.com/erutsiom/p/9904567.html
洛谷P 1979華容道題解
NOIP 2018まであと7日で問題解を書いて人柄を蓄える
(初めて紫問題の問題解を書いたのはまだ少し興奮している)
いくつかの説明
1、本題解とコード中の0/1/2/3はそれぞれ上/下/左/右を表す
2、明確な表現のために、問題解には目標駒(タイトルの中の(SX,SY)が(B)、目標格子(タイトルの中の(TX,TY)が)(C)、空白格子が(E)
【考え方分析】何人かのdalaoが言ったように、この問題の建図は実行可能な状態をエッジにつなぎ、質問するたびに最短ルートを走ることである.
私が$ok[i][j][0/1/2/3]$で(B)が点((i,j))にある場合、4方向に空き格子がある可能性があるかどうか(各グループのクエリで空き格子が到達できるかどうかは考慮せず、その格子が固定格子であるかどうか、または境界を越えているかどうかのみを考慮する.)
このセクションのコードは次のとおりです.
//
for(int i=1;i<=n;i++)//
for(int j=1;j<=m;j++){
if(!mapp[i][j])continue;//
for(int k=0;k<4;k++)//
if(judge(i+xx[k],j+yy[k]))ok[i][j][k]=1;
}
judge関数は、空白または境界であるかどうかを判断するために使用されます.
bool judge(int ax,int ay){
if(ax<=0||ax>n||ay<=0||ay>m)return 0;//
return mapp[ax][ay];
}
図面を作成するために、私は状態を1次元配列に保存します:格子の番号:上から下へ左から右へ編みます
\(e.g.\)
ステータスの番号(e.g.)
1番グリッドの4つのステータス番号は0123です.
すると、次の番号付け関数が得られます.
int getnum(int ax,int ay,int t){
return ((ax-1)*m+ay)*4-(4-t);
}//t=0/1/2/3
(q)グループが尋ねる地図の状況は同じなので、先に図を建てることができます.
どのような2つの状態がエッジをつなぐことができますか?
2つの状況を考慮します.
・空白の格子が(B)を上下左右にぐるぐる回っている
bfsで乱転が少なくとも何回上から下へ、左から右へ...
注意が必要なのは、乱転時(B)は動けません!!!(ここは長い間QQQQをしていました)
・空白格子と(B)交換位置
両方のステータスが存在することを保証する必要があります.
距離1の辺をつなげてください.
int bfs(int dx,int dy,int sx,int sy,int tx,int ty){//
//(sx,sy) (tx,ty), (dx,dy)
queueq;
memset(vis,0,sizeof vis);
white st;st.x=sx;st.y=sy;
st.step=0;vis[sx][sy]=1;
q.push(st);
while(!q.empty()){
white noww=q.front();
q.pop();
if(noww.x==tx&&noww.y==ty)//
return noww.step;
for(int i=0;i<4;i++){//
if(judge(noww.x+xx[i],noww.y+yy[i])){//
if(vis[noww.x+xx[i]][noww.y+yy[i]])continue;//
if(noww.x+xx[i]==dx&&noww.y+yy[i]==dy)continue;//
white nxt;
nxt.x=noww.x+xx[i];
nxt.y=noww.y+yy[i];
nxt.step=noww.step+1;
q.push(nxt);vis[noww.x+xx[i]][noww.y+yy[i]]=1;
}
}
}
return inf;//
}
駒が動かず、空白格が乱転する場合:
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<4;k++)
for(int l=k+1;l<4;l++){
if(ok[i][j][k]&&ok[i][j][l]){//
int aa=getnum(i,j,k);
int bb=getnum(i,j,l);
int cc=bfs(i,j,i+xx[k],j+yy[k],i+xx[l],j+yy[l]);
if(cc==inf)continue;
add(aa,bb,cc);add(bb,aa,cc);
}
}
qwq
for(int i=1;i<=n;i++)//
for(int j=1;j
これで初期化が完了しました!(プラスエッジの操作は普通の図論と同じw)
各グループの質問について、まず特審します.
while(q--){
scanf("%d%d%d%d%d%d",&ex,&ey,&bx,&by,&cx,&cy);
if(bx==cx&&by==cy){
puts("0");
continue;
}
if(!mapp[cx][cy]){
puts("-1");
continue;
}
if(!mapp[bx][by]){
puts("-1");
continue;
}
work();
}
そして、最初の状態をどのように図に移すかを考えます.
空白格が(B)に隣接する状況しか存在しないので、so暴力は空白格を(B)の4つの方向に走らせようと試みるとよい
for(int i=0;i<4;i++){//
if(judge(bx+xx[i],by+yy[i])){//
int nw=bfs(bx,by,ex,ey,bx+xx[i],by+yy[i]);
if(nw==inf)continue;//
int nq=getnum(bx,by,i);
d[nq]=nw;
Q.push(nq);
viss[nq]=1;
}
}
そして、楽しくSPFAを走ります
while(!Q.empty()){
int noww=Q.front();Q.pop();viss[noww]=0;
for(int j=head[noww];j;j=b[j].nxt){
int vv=b[j].to;
if(d[vv]>d[noww]+b[j].dis){
d[vv]=d[noww]+b[j].dis;
if(!viss[vv])Q.push(vv),viss[vv]=1;
}
}
}
最後に、到着できるかどうかを楽しくチェックします(C)
int ans=inf;
for(int i=0;i<4;i++){
int qaq=getnum(cx,cy,i);
ans=min(ans,d[qaq]);
}
if(ans==inf)puts("-1");
else printf("%d
",ans);
アノテーションコードQWQを貼る
#include
using namespace std;
const int MAXN=35;
const int inf=99999999;
int n,m,q,ex,ey,bx,by,cx,cy;
bool mapp[MAXN][MAXN];
int xx[4]={-1,1,0,0};
int yy[4]={0,0,-1,1};
int getnum(int ax,int ay,int t){
return ((ax-1)*m+ay)*4-(4-t);
}
struct white{
int x,y;
int step;
};
bool judge(int ax,int ay){
if(ax<=0||ax>n||ay<=0||ay>m)return 0;
return mapp[ax][ay];
}
bool vis[MAXN][MAXN];
int bfs(int dx,int dy,int sx,int sy,int tx,int ty){
queueq;
memset(vis,0,sizeof vis);
white st;st.x=sx;st.y=sy;
st.step=0;vis[sx][sy]=1;
q.push(st);
while(!q.empty()){
white noww=q.front();
q.pop();
if(noww.x==tx&&noww.y==ty)
return noww.step;
for(int i=0;i<4;i++){
if(judge(noww.x+xx[i],noww.y+yy[i])){
if(vis[noww.x+xx[i]][noww.y+yy[i]])continue;
if(noww.x+xx[i]==dx&&noww.y+yy[i]==dy)continue;
white nxt;
nxt.x=noww.x+xx[i];
nxt.y=noww.y+yy[i];
nxt.step=noww.step+1;
q.push(nxt);vis[noww.x+xx[i]][noww.y+yy[i]]=1;
}
}
}
return inf;
}
struct edge{
int to,nxt,dis;
}b[5005];
int head[5005],tot;
void add(int u,int v,int w){
b[++tot].to=v;b[tot].nxt=head[u];
b[tot].dis=w;head[u]=tot;
}
bool ok[MAXN][MAXN][5];
void init(){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(!mapp[i][j])continue;
for(int k=0;k<4;k++)
if(judge(i+xx[k],j+yy[k]))ok[i][j][k]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<4;k++)
for(int l=k+1;l<4;l++){
if(ok[i][j][k]&&ok[i][j][l]){
int aa=getnum(i,j,k);
int bb=getnum(i,j,l);
int cc=bfs(i,j,i+xx[k],j+yy[k],i+xx[l],j+yy[l]);
if(cc==inf)continue;
add(aa,bb,cc);add(bb,aa,cc);
}
}
for(int i=1;i<=n;i++)
for(int j=1;jQ;
bool viss[5005];
int d[5005];
void work(){
memset(d,128/3,sizeof d);
memset(viss,0,sizeof viss);
for(int i=0;i<4;i++){
if(judge(bx+xx[i],by+yy[i])){
int nw=bfs(bx,by,ex,ey,bx+xx[i],by+yy[i]);
if(nw==inf)continue;
int nq=getnum(bx,by,i);
d[nq]=nw;
Q.push(nq);
viss[nq]=1;
}
}
while(!Q.empty()){
int noww=Q.front();Q.pop();viss[noww]=0;
for(int j=head[noww];j;j=b[j].nxt){
int vv=b[j].to;
if(d[vv]>d[noww]+b[j].dis){
d[vv]=d[noww]+b[j].dis;
if(!viss[vv])Q.push(vv),viss[vv]=1;
}
}
}
int ans=inf;
for(int i=0;i<4;i++){
int qaq=getnum(cx,cy,i);
ans=min(ans,d[qaq]);
}
if(ans==inf)puts("-1");
else printf("%d
",ans);
}
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)cin>>mapp[i][j];
init();
while(q--){
scanf("%d%d%d%d%d%d",&ex,&ey,&bx,&by,&cx,&cy);
if(bx==cx&&by==cy){
puts("0");
continue;
}
if(!mapp[cx][cy]){
puts("-1");
continue;
}
if(!mapp[bx][by]){
puts("-1");
continue;
}
work();
}
return 0;
}
终わって花を撒きます!!!
by Erutsiom
転載先:https://www.cnblogs.com/erutsiom/p/9904567.html