CF1316D【Nash Matrix】(dfs+构造+思维)
图论2000分
题意:需要构造一个n×n的矩阵,每个位置上有一个符号‘U’,‘D’,‘L’,‘R’,‘X’。分别表示上下左右和停止。每个坐标会有一个x,y。假设当前坐标为i,j且上面值为x,y则表示从i,j为起点会在x,y的地方终止。当(x,y)=(-1,-1)表示无法终止,当然要保证在n×n的范围内。
问是否能构造出这样的矩阵,不能就输出“INVALID”。能就输出“VALID”和构造的矩阵。
题解:学会正向思考与反向dfs相结合,这里主要运用了从终点开始反向dfs的思路,具体我们一步一步分析。我们遍历每一个点u(i,j),如果其终点是(-1,-1),那么如果合法的话它的周边必定也存在终点为(-1,-1)的点v,我们将该点u与v相连,mp[i][j]即该点u的操作方向,指向v。倘若其身边不存在这样的(-1,-1)那么直接输出INVALID终止即可。
接下来我们思考如果该点存有终点(即终点不为(-1,-1)的情况),那么其终点所代表的的mp必定为终点本身的坐标这无可置疑。所以我们先特判一下,如果不等于直接输出INVALID终止程序。否则我们从终点开始遍历,寻找其四周的边开始dfs,最后回到出发点看出发点的mp是否存在,如果不存在说明终点回不到出发点,那么说明也是INVALID的情况。
具体看代码吧,我觉得这是一道很不错的题,很考验思维
AC代码:
#include<bits/stdc++.h> #pragma GCC optimize(2) #define ll long long #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl '\n' #define eps 0.000000001 #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define IO ios::sync_with_stdio(false);cin.tie(0); using namespace std; const int INF=0x3f3f3f3f; const ll inf=0x3f3f3f3f3f3f3f3f; const int mod=1e9+7; const int maxn=1e3+5; struct node{ int x,y; }a[maxn][maxn]; int dx[4]={0,1,0,-1}; int dy[4]={1,0,-1,0}; char mp[maxn][maxn]; char ch[]="RDLU"; char ch1[]="LURD"; int n; void dfs(int x,int y){ rep(k,0,3){ int xx=x+dx[k],yy=y+dy[k]; if(xx<1||yy<1||xx>n||yy>n||mp[xx][yy]) continue; if(a[x][y].x==a[xx][yy].x&&a[x][y].y==a[xx][yy].y){ mp[xx][yy]=ch1[k]; dfs(xx,yy); } } } int main(){ scanf("%d",&n); rep(i,1,n){ rep(j,1,n){ scanf("%d%d",&a[i][j].x,&a[i][j].y); } } rep(i,1,n){ rep(j,1,n){ if(a[i][j].x==-1){ rep(k,0,3){ int xx=i+dx[k],yy=j+dy[k]; if(xx<1||yy<1||xx>n||yy>n) continue; if(a[xx][yy].x==-1){ mp[i][j]=ch[k]; break; } } } else{ if(mp[a[i][j].x][a[i][j].y]&&mp[a[i][j].x][a[i][j].y]!='X'){ cout<<"INVALID"<<endl; return 0; } mp[a[i][j].x][a[i][j].y]='X'; dfs(a[i][j].x,a[i][j].y); } if(!mp[i][j]){ cout<<"INVALID"<<endl; return 0; } } } puts("VALID"); rep(i,1,n){ rep(j,1,n){ cout<<mp[i][j]; } puts(""); } return 0; }
前ICPC算法竞赛退役选手|现摸鱼ing