Robots on a Grid CodeForces - 1335F(拓扑排序+正反建图+判环)

There is a rectangular grid of size n×m. Each cell of the grid is colored black (‘0’) or white (‘1’). The color of the cell (i,j) is ci,j. You are also given a map of directions: for each cell, there is a direction si,j which is one of the four characters ‘U’, ‘R’, ‘D’ and ‘L’.

If si,j is ‘U’ then there is a transition from the cell (i,j) to the cell (i−1,j);
if si,j is ‘R’ then there is a transition from the cell (i,j) to the cell (i,j+1);
if si,j is ‘D’ then there is a transition from the cell (i,j) to the cell (i+1,j);
if si,j is ‘L’ then there is a transition from the cell (i,j) to the cell (i,j−1).
It is guaranteed that the top row doesn’t contain characters ‘U’, the bottom row doesn’t contain characters ‘D’, the leftmost column doesn’t contain characters ‘L’ and the rightmost column doesn’t contain characters ‘R’.

You want to place some robots in this field (at most one robot in a cell). The following conditions should be satisfied.

Firstly, each robot should move every time (i.e. it cannot skip the move). During one move each robot goes to the adjacent cell depending on the current direction.
Secondly, you have to place robots in such a way that there is no move before which two different robots occupy the same cell (it also means that you cannot place two robots in the same cell). I.e. if the grid is “RL” (one row, two columns, colors does not matter there) then you can place two robots in cells (1,1) and (1,2), but if the grid is “RLL” then you cannot place robots in cells (1,1) and (1,3) because during the first second both robots will occupy the cell (1,2).
The robots make an infinite number of moves.

Your task is to place the maximum number of robots to satisfy all the conditions described above and among all such ways, you have to choose one where the number of black cells occupied by robots before all movements is the maximum possible. Note that you can place robots only before all movements.

You have to answer t independent test cases.

Input
The first line of the input contains one integer t (1≤t≤5⋅104) — the number of test cases. Then t test cases follow.

The first line of the test case contains two integers n and m (1<nm≤106) — the number of rows and the number of columns correspondingly.

The next n lines contain m characters each, where the j-th character of the i-th line is ci,j (ci,j is either ‘0’ if the cell (i,j) is black or ‘1’ if the cell (i,j) is white).

The next n lines also contain m characters each, where the j-th character of the i-th line is si,j (si,j is ‘U’, ‘R’, ‘D’ or ‘L’ and describes the direction of the cell (i,j)).

It is guaranteed that the sum of the sizes of fields does not exceed 106 (∑nm≤106).

Output
For each test case, print two integers — the maximum number of robots you can place to satisfy all the conditions described in the problem statement and the maximum number of black cells occupied by robots before all movements if the number of robots placed is maximized. Note that you can place robots only before all movements.

Example
Input
3
1 2
01
RL
3 3
001
101
110
RLL
DLD
ULL
3 3
000
000
000
RRD
RLD
ULL
Output
2 1
4 3
2 2
题意:有一个包含n*m个格子的图形,每一个格子被染成黑色(0)或者白色(1)。每一个格子都有指定的指向,或上或下或左或右。每一个格子最多只能放置一个机器人,所有的机器人一起移动,不允许多个机器人处在同一个格子,时间是无限长的。问最多可以放置多少个机器人。在这一前提下,最多有多少机器人一开始可以放置在黑色的格子里。
思路:因为时间是无限长的,所以若想满足条件,只能无限循环,这就要求我们去找这个有向图中的所有的环,求环之前需要拓扑排序一下,将不在环中的点都给处理掉。第一个答案就是所有环的长度加起来了。那么第二个答案怎么弄呢?如图所示:
在这里插入图片描述
假如1的颜色是白色,2的颜色是白色,3的颜色是黑色的话,我们一开始在2,3放置机器人,那么第二个答案就是1,这样的话是最大的。因此,我们在dfs找环的时候,就把这个环延伸出去的单链也处理一下,找出这些单链以及环上面的黑色的点。但是我们怎么判断能不能在这个点上放置机器人呢?如图所示:
在这里插入图片描述
dis数组就是dfs的过程中处理出来的,类似于树中的深度。这个图,我们可以看到第二个答案是2,在2或者4或者6,5放置的时候,这样是最大的,我们可以发现,2和4和6对环的长度2取余都是0,他们不能同时放置机器人,而5对环的长度2取余是1,可以和2,4,6同时放置,也就是dis[i]%len这个数所代表的的点上只能放置一个(len代表环的长度)。上面那个图怎样处理出dis数组呢?我们肯定是从环上面的某一点出发,这样的话,我们反向建图,然后就可以处理出来了。
总结一下:一开始正反建图,正向建图是为了拓扑排序,处理出环;反向建图是为了从环上某一点出发,处理出dis数组,从而求出答案2.
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxx=1e6+100;
string s1[maxx];
string s2[maxx];
vector<int> in[maxx],out[maxx],bck[maxx];
int vis[maxx],deg[maxx],dis[maxx],vis1[maxx];
int n,m;

inline void init()
{
	for(int i=0;i<=n*m+1;i++) deg[i]=0,vis[i]=0,in[i].clear(),out[i].clear(),dis[i]=0,vis1[i]=0,bck[i].clear();
}
inline int get_pos(int x,int y)
{
	return x*m+y;
}
inline void Topo()
{
	queue<int> q;
	for(int i=0;i<n*m;i++) if(deg[i]==1) q.push(i);
	while(q.size())
	{
		int u=q.front();
		q.pop();
		deg[u]--;
		for(int i=0;i<in[u].size();i++)
		{
			deg[in[u][i]]--;
			if(deg[in[u][i]]==1) q.push(in[u][i]);
		}
	}
}
inline void dfs(int u,int f,int step,int &num)
{
	dis[u]=step;
	vis[u]=1;
	if(s1[u/m][u%m]=='0') bck[f].push_back(u);
	for(int i=0;i<out[u].size();i++)
	{
		if(vis[out[u][i]])//这个点之前处理过,因为是有向图,所以遇到之前处理过的点,说明在环上循环。那么当前的步数,就是环的长度了。
		{
			num=step;
			continue;
		}
		dfs(out[u][i],f,step+1,num);
	}
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		init();
		for(int i=0;i<n;i++) cin>>s1[i];
		for(int i=0;i<n;i++) cin>>s2[i];
		int tx,cx;
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				cx=get_pos(i,j);
				if(s2[i][j]=='R') tx=get_pos(i,j+1);
				if(s2[i][j]=='L') tx=get_pos(i,j-1);
				if(s2[i][j]=='U') tx=get_pos(i-1,j);
				if(s2[i][j]=='D') tx=get_pos(i+1,j);
				in[cx].push_back(tx);
				out[tx].push_back(cx);
				deg[cx]++,deg[tx]++;
			}
		}
		Topo();
		int ans1=0,ans2=0,num=0;
		for(int i=0;i<n*m;i++)
		{
			if(deg[i]&&!vis[i])
			{
				dfs(i,i,1,num=0);
				ans1+=num;
				for(int j=0;j<bck[i].size();j++)
				{
					if(vis1[dis[bck[i][j]]%num]==0)
					{
						vis1[dis[bck[i][j]]%num]=1;
						ans2++;
					}
				}
				for(int j=0;j<bck[i].size();j++) vis1[dis[bck[i][j]]%num]=0;//在这里还要都归零,不要影响下次使用
			}
		}
		printf("%d %d\n",ans1,ans2);
	}
	return 0;
}

努力加油a啊,(o)/~

发布了668 篇原创文章 · 获赞 118 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/starlet_kiss/article/details/105555915
今日推荐