1. 程式人生 > 實用技巧 >CF1316D【Nash Matrix】(dfs+構造+思維)

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; }
View Code