Codeforces Round #753 (Div. 3) F. Robot on the Board 2解题报告

发布于 2021-11-08  633 次阅读


第一次写过一个通过人数这么少的题,还没看题解,芜湖!!!

原题链接:https://codeforces.com/contest/1607/problem/F

大致来说说这道题解题思路。在每个网格块上都有个字母来指引往哪个方向去走,所以我们可以将其转换为图论问题来解决。且每个点都只有一个对外连出的边。那么这个问题就变成了选择起始点,找到当前点能走的最长路径。此时出了一个问题是,构建出的这个图是有环的,且每个点不能经过第二次。经过一番思索我们可以将一个环缩成一个点,只要走到这个点就相当于把环里面的所有点都给走了一遍。那么如何去找环,并获取到环的尺寸?可以先拓扑一下,这样未成环的点都会被过滤掉,剩下的环dfs一遍,能获取到每个环的尺寸。嗯,问题解决了

上代码

#include <bits/stdc++.h>
using namespace std;
char s[2005][2005];
vector<int> nxt,d,in;
vector<bool> used;
int n,m;
void cal(int st,int now,int step){
	if(nxt[now]==st){
		d[now]=step+1;
		return;
	}
	cal(st,nxt[now],step+1);
	d[now]=d[nxt[now]];
}
void topo(){
	queue<int>q;
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
		if(in[(i-1)*m+j]==0) q.push((i-1)*m+j);
	while(q.size()){
		int now=q.front();q.pop();
		if(nxt[now]){
			in[nxt[now]]--;
			if(in[nxt[now]]==0){
				q.push(nxt[now]);
			}
		}
	}
}
void dfs(int x,int y){
	int nx=x,ny=y;
	if(s[x][y]=='L') ny--;
	if(s[x][y]=='R') ny++;
	if(s[x][y]=='U') nx--;
	if(s[x][y]=='D') nx++;
	if(nx<1||nx>n||ny<1||ny>m) return;
	nxt[(x-1)*m+y]=(nx-1)*m+ny;
	in[(nx-1)*m+ny]++;
}
int get(int now){
	if(d[now]) return d[now];
	d[now]=1;
	//cout<<now<<endl;
	if(nxt[now]){
		//used[nxt[now]]=1;
		d[now]=get(nxt[now])+1;
		//used[nxt[now]]=0;
	}
	return d[now];
}
int main(){
	int T;
	cin>>T;
	while(T--){
		in.clear(),nxt.clear(),d.clear();
		scanf("%d%d",&n,&m);
		in.resize(n*m+5),nxt.resize(n*m+5),d.resize(n*m+5);
		for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
		for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			dfs(i,j);
		}
		topo();
		for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			if(d[(i-1)*m+j]==0&&in[(i-1)*m+j]) cal((i-1)*m+j,(i-1)*m+j,0);
		}
		int ans=0,ansx=0,ansy=0;
		for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			//cout<<d[2]<<endl;
			get((i-1)*m+j);
			//cout<<d[2]<<endl;
			if(d[(i-1)*m+j]>ans){
				ans=d[(i-1)*m+j];
				ansx=i,ansy=j;
			}	
		}
		printf("%d %d %d\n",ansx,ansy,ans);
	}
	return 0;
}

回忆这理想不够理想,沿途逛世间一趟只有向上