// Problem: P5372 [SNOI2019] 积木 // Contest: Luogu ...

Creado el: 18 de agosto de 2026

Respondido usando GPT-5.6 Thinking por Chat01

Pregunta

// Problem: P5372 [SNOI2019] 积木
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P5372
// Memory Limit: 500 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define llg long long
#define pb push_back
#define pii pair <int,int>
using namespace std;
const int MAXN=2005;
int rd() {
char cr=getchar();int f=1,x=0;
while (cr<'0'||cr>'9'){if (cr=='-') {f=-1;}cr=getchar();}
while (cr>='0'&&cr<='9'){x*=10;x+=cr-'0';cr=getchar();}
return f*x;
}
int n,m,sx,sy,ex,ey; pii nA[MAXN][MAXN],nB[MAXN][MAXN];
bool vis[MAXN][MAXN],ip[MAXN][MAXN]; string ans="";
char c1[MAXN][MAXN],c2[MAXN][MAXN]; pii gt(int x,int y,char c) {
if (c=='n') return {x+1,y};
if (c=='u') return {x-1,y};
if (c=='<') return {x,y+1};
if (c=='>') return {x,y-1};
return {0,0};
} void mv(int x,int y,int vx,int vy) {
int wx=nA[vx][vy].first,wy=nA[vx][vy].second;
if (vx==x-1) ans+='U';
else if (vx==x+1) ans+='D';
else if (vy==y-1) ans+='L';
else if (vy==y+1) ans+='R';
nA[x][y]={vx,vy}; nA[vx][vy]={x,y}; nA[wx][wy]={0,0};
} void fp() {
int cx=sx,cy=sy; while (cx!=ex||cy!=ey) {
ip[cx][cy]=1; int bx=nB[cx][cy].first,by=nB[cx][cy].second;
if (bx==0&&by==0) break; ip[bx][by]=1;
cx=nA[bx][by].first; cy=nA[bx][by].second;
} ip[ex][ey]=1;
} void dfs(int x,int y) {
vis[x][y]=1; int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int bx=nB[x][y].first,by=nB[x][y].second;
for (int i=0;i<4;i++) {
int vx=x+dx[i],vy=y+dy[i];
if (vx>=1&&vx<=n&&vy>=1&&vy<=m&&!ip[vx][vy]&&c1[vx][vy]!=c2[vx][vy]) {
if (vx==bx&&vy==by) continue;
int wx=nA[vx][vy].first,wy=nA[vx][vy].second;
if (wx!=0&&!vis[wx][wy]&&!vis[vx][vy]) {
vis[vx][vy]=1; mv(x,y,vx,vy); dfs(wx,wy);
}
}
} if (x==ex&&y==ey) return;
if (bx!=0&&by!=0) {
int nx=nA[bx][by].first,ny=nA[bx][by].second;
vis[bx][by]=1; mv(x,y,bx,by);
if (!vis[nx][ny]) dfs(nx,ny);
}
}
signed main() {
cin>>n>>m;
for (int i=1;i<=n;i++) {
for (int j=1;j<=m;j++) {
cin>>c1[i][j];
}
}for (int i=1;i<=n;i++) {
for (int j=1;j<=m;j++) {
cin>>c2[i][j];
}
} for (int i=1;i<=n;i++) {
for (int j=1;j<=m;j++) {
nA[i][j]=gt(i,j,c1[i][j]); if (nA[i][j].first==0&&c1[i][j]=='o') {sx=i; sy=j;}
nB[i][j]=gt(i,j,c2[i][j]); if (nB[i][j].first==0&&c2[i][j]=='o') {ex=i; ey=j;}
}
} fp(); dfs(sx,sy);
cout<<ans<<"\n";
return 0;
}DEBUG找错误,根据我的代码风格最小限度修改

Python

python
from functools import lru_cache def gen_matchings(n,m): N=n*m res=[] def rec(used, pairs): # allow exactly one hole; brute choose hole first pass # generate perfect-near matchings by choosing hole and domino tilings def tilings_with_hole(n,m,hole): used=[False]*(n*m) used[hole]=True pairs=[] out=[] def dfs(): try: u=next(i for i,x in enumerate(used) if not x) except StopIteration: out.append(tuple(sorted(tuple(sorted(p)) for p in pairs))) return x,y=divmod(u,m) used[u]=True for dx,dy in [(1,0),(-1,0),(0,1),(0,-1)]: xx,yy=x+dx,y+dy if 0<=xx<n and 0<=yy<m: v=xx*m+yy if not used[v]: used[v]=True;pairs.append((u,v)) dfs() pairs.pop();used[v]=False used[u]=False dfs() return out def all_states(n,m): states=[] seen=set() for h in range(n*m): for p in tilings_with_hole(n,m,h): if p not in seen: seen.add(p); states.append((h,p)) return states states=all_states(3,3) len(states) 18

Python

python
def accepted_pair_algo(n,m,stateA,stateB,limit=100000): hA,pA=stateA; hB,pB=stateB; N=n*m A=[None]*N; B=[None]*N for a,b in pA:A[a]=b;A[b]=a for a,b in pB:B[a]=b;B[b]=a hole=hA ans=[] vis=[False]*N def neigh(u): x,y=divmod(u,m) for dx,dy,ch in [(-1,0,'U'),(1,0,'D'),(0,-1,'L'),(0,1,'R')]: xx,yy=x+dx,y+dy if 0<=xx<n and 0<=yy<m: yield xx*m+yy,ch def step(v): nonlocal hole w=A[v] if w is None: raise RuntimeError(("v hole",hole,v)) hx,hy=divmod(hole,m); vx,vy=divmod(v,m) if abs(hx-vx)+abs(hy-vy)!=1: raise RuntimeError(("not adj",hole,v)) if vx==hx-1: ans.append('U') elif vx==hx+ (0, 13, [])

Python

python
def user_algo_variant(n,m,stateA,stateB,use_dynamic=False,limit=10000): hA,pA=stateA; hB,pB=stateB N=n*m A=[None]*N; B=[None]*N for a,b in pA: A[a]=b; A[b]=a for a,b in pB: B[a]=b; B[b]=a c1=chars_from_state(n,m,*stateA); c2=chars_from_state(n,m,*stateB) sx=hA; ex=hB; ip=[False]*N; vis=[False]*N; ans=[] cx=sx while cx!=ex: ip[cx]=1; bx=B[cx] if bx is None: break ip[bx]=1; cx=A[bx] if cx is None: break ip[ex]=1 def neigh(u): x,y=divmod(u,m) for dx,dy in [(-1,0),(1,0),(0,-1),(0,1)]: xx,yy=x+dx,y+dy if 0<=xx<n and 0<=yy<m: yield xx*m+yy def mv(x,v): w=A[v] if w is None: raise RuntimeError A[x]=v; A[v]=x; A[w]=None; ans.append(1) import sys;sys.setrecursionlimit(1000000) def dfs(x): vis[x]=1; bx=B[x] for v in neigh(x): cond = A[v]!=B[v] if use_dynamic else c1[v]!=c2[v] if not

Pensamiento

Evaluated paired-grid correction traversal

Worked for 2m 13s

Respuesta

定位到了,核心不是 mv(),而是你现在的 dfs() 搜索范围不对

题目的一次操作本质上是:空格选一个相邻积木的一端,把积木移入空格,新的空格变成这块积木原来的另一端。(luogu.com.cn)

你这里:

cpp
if (vx>=1&&vx<=n&&vy>=1&&vy<=m&&!ip[vx][vy]&&c1[vx][vy]!=c2[vx][vy])

要求 DFS 只能经过初始状态和目标状态不同的格子。这是不成立的。为了找到远处的差异环,搜索过程必须允许经过已经正确的积木。

这个反例你的程序直接输出空串:

text
3 3 o<> nnn uuu o<> n<> u<>

右下角 2*2 显然还不同,但空格旁边两个格子都是 c1==c2,所以你的 DFS 根本走不进去。

最小修改方案

你的 gt()mv()nA/nB 全部可以保留。fp() 和原来的 dfs() 换掉即可。

新增一个 step():在真实空格处走一步,同时更新 sx,sy

cpp
void step(int vx,int vy) { int nx=nA[vx][vy].first,ny=nA[vx][vy].second; mv(sx,sy,vx,vy); sx=nx; sy=ny; }

然后把 fp() 换成:

cpp
void walk(int x,int y) { while (sx!=x||sy!=y) { int vx=nB[sx][sy].first,vy=nB[sx][sy].second; step(vx,vy); } }

这里的意义是:不断把“目标状态下应该覆盖当前空格的积木”移过来,直到真实空格走到 (x,y)

然后把你的 dfs() 整个替换成:

cpp
void dfs(int x,int y) { if (vis[x][y]) return; vis[x][y]=1; int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1}; for (int i=0;i<4;i++) { int vx=x+dx[i],vy=y+dy[i]; if (vx<1||vx>n||vy<1||vy>m||vis[vx][vy]) continue; int nx=nB[vx][vy].first,ny=nB[vx][vy].second; if (nx==0&&ny==0) continue; if (nA[vx][vy]!=nB[vx][vy]) { step(vx,vy); walk(nx,ny); step(vx,vy); } step(vx,vy); vis[vx][vy]=1; dfs(nx,ny); step(vx,vy); } }

最后 main 里:

cpp
fp(); dfs(sx,sy);

改成:

cpp
walk(ex,ey); dfs(ex,ey);

就行。

也就是说,你原来的:

cpp
bool vis[MAXN][MAXN],ip[MAXN][MAXN];

可以暂时不管 ip,它已经没用了。fp() 也可以直接删掉。


按你原风格改完的完整版本

cpp
#include <bits/stdc++.h> #define llg long long #define pb push_back #define pii pair <int,int> using namespace std; const int MAXN=2005; int rd() { char cr=getchar();int f=1,x=0; while (cr<'0'||cr>'9'){if (cr=='-') {f=-1;}cr=getchar();} while (cr>='0'&&cr<='9'){x*=10;x+=cr-'0';cr=getchar();} return f*x; } int n,m,sx,sy,ex,ey; pii nA[MAXN][MAXN],nB[MAXN][MAXN]; bool vis[MAXN][MAXN]; string ans=""; char c1[MAXN][MAXN],c2[MAXN][MAXN]; pii gt(int x,int y,char c) { if (c=='n') return {x+1,y}; if (c=='u') return {x-1,y}; if (c=='<') return {x,y+1}; if (c=='>') return {x,y-1}; return {0,0}; } void mv(int x,int y,int vx,int vy) { int wx=nA[vx][vy].first,wy=nA[vx][vy].second; if (vx==x-1) ans+='U'; else if (vx==x+1) ans+='D'; else if (vy==y-1) ans+='L'; else if (vy==y+1) ans+='R'; nA[x][y]={vx,vy}; nA[vx][vy]={x,y}; nA[wx][wy]={0,0}; } void step(int vx,int vy) { int nx=nA[vx][vy].first,ny=nA[vx][vy].second; mv(sx,sy,vx,vy); sx=nx; sy=ny; } void walk(int x,int y) { while (sx!=x||sy!=y) { int vx=nB[sx][sy].first,vy=nB[sx][sy].second; step(vx,vy); } } void dfs(int x,int y) { if (vis[x][y]) return; vis[x][y]=1; int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1}; for (int i=0;i<4;i++) { int vx=x+dx[i],vy=y+dy[i]; if (vx<1||vx>n||vy<1||vy>m||vis[vx][vy]) continue; int nx=nB[vx][vy].first,ny=nB[vx][vy].second; if (nx==0&&ny==0) continue; if (nA[vx][vy]!=nB[vx][vy]) { step(vx,vy); walk(nx,ny); step(vx,vy); } step(vx,vy); vis[vx][vy]=1; dfs(nx,ny); step(vx,vy); } } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin>>n>>m; for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) { cin>>c1[i][j]; } } for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) { cin>>c2[i][j]; } } for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) { nA[i][j]=gt(i,j,c1[i][j]); if (nA[i][j].first==0&&c1[i][j]=='o') {sx=i; sy=j;} nB[i][j]=gt(i,j,c2[i][j]); if (nB[i][j].first==0&&c2[i][j]=='o') {ex=i; ey=j;} } } walk(ex,ey); dfs(ex,ey); cout<<ans<<"\n"; return 0; }

我对这版用 3×3 全部合法局面两两组合以及 3×5 全部合法局面两两组合做了验证,没有再发现转换错误。

你原思路离正确其实很近,关键区别就是:差异边组成的环可能离空格很远,DFS 搜索时必须穿过“已经正确”的区域;搜索位置 (x,y) 和真正的空格 sx,sy 不能始终强行视作同一个概念。

Compartir este Q&A