Codeforces 1316D Nash Matrix

Description

有一种用 $n imes n$ 的网格玩的游戏。

  • 当 $(i,j)$ 填的是 L 时,你会走到 $(i, j - 1)$;
  • 当 $(i,j)$ 填的是 R 时,你会走到 $(i, j + 1)$;
  • 当 $(i,j)$ 填的是 U 时,你会走到 $(i - 1, j )$;
  • 当 $(i,j)$ 填的是 D 时,你会走到 $(i + 1, j)$;
  • 当 $(i,j)$ 填的是 X 时,你将不动。

当你从 $(i, j)$ 出发,最后将会停止在 $(x_{(i, j)}, y_{(i, j)})$。或者,如果你永远不会停止,$(x_{(i, j)}, y_{(i, j)})$ 是 $(-1, -1)$。

现在给出所有的 $(x_{(i, j)}, y_{(i, j)})$,试构造出原网格。如果无法构造,输出 INVALID,否则输出 VALID,并输出一种合法网格。

Solution

分两个部分,第一部分处理会终止的结点,第二部分处理不会终止的结点

试想,对于一个 $(i, j)$,停止于 $(ex_{(i, j)}, ey_{(i, j)})$,那么,我们先随便拉出来一条路径,一定会知道,路径上的每一个点都会停止于 $ {(ex_{(i, j)}, ey_{(i, j)})}$,所以,这张图一定是若干个连通块,某一个连通块内,点的停止点应该是相同的。

我们找到所有的自停止点,也就是 $(i, j) = (ex_{(i, j)}, ey_{(i, j)})$,显然这个点应当是 X,然后我们从它开始,在满足停止点是它的连通块内构造答案。这很简单,只要我们 DFS 一遍,把访问到一个点的方向都反过来就行了。

void DFS(int p, int q, int sx, int sy) // 当前在 (p, q),处理所有停止点是 (sx, sy) 的
{
	REP(i, 0, 3) // 枚举方向,dx[], dy[] 是增量数组
	{
		int tx = p + dx[i], ty = q + dy[i];
		if(tx >= 1 && tx <= n && ty >= 1 && ty <= n && // 不越界
		  ex[tx][ty] == sx && ey[tx][ty] == sy && !ans[tx][ty]) // 终止点是 (sx, sy) && 没访问
		{
			ans[tx][ty] = dc[i]; // dc[] 存的是反方向
			DFS(tx, ty, sx, sy);
		}
	}
}

然后是 $-1$ 的情况。如果一个 $-1$ 连通块的大小为 $1$,那么结果肯定是 INVALID,因为一个点怎么也没法做到不停止。否则,我们选择这个连通块内相邻的两个点,把它们指向对方,然后让其他 $-1$ 都走到这两个点上面来,这个连通块就合法了。

这需要再写一种 DFS 吗?答案是否定的,我们把上面 DFS 的参数 $(sx ,s y)gets (-1, -1)$,就是自动在找 $-1$ 连通块了。

别忘了构造题的惯常套路:构造完后再检验一遍。

#include <bits/stdc++.h>
#define REP(i, x, y) for(register int i = x; i <= y; i++)
using namespace std;
const int N = 1e3 + 5;
const int dx[4] = {0, 1, 0, -1};
const int dy[4] = {1, 0, -1, 0};
const char dc[4] = {'L', 'U', 'R', 'D'};
int n, ex[N][N], ey[N][N];
char ans[N][N];
void DFS(int p, int q, int sx, int sy)
{
    REP(i, 0, 3)
    {
        int tx = p + dx[i], ty = q + dy[i];
        if(tx >= 1 && tx <= n && ty >= 1 && ty <= n &&
          ex[tx][ty] == sx && ey[tx][ty] == sy && !ans[tx][ty])
        {
            ans[tx][ty] = dc[i];
            DFS(tx, ty, sx, sy);
        }
    }
}
int main()
{
    scanf("%d", &n);
    REP(i, 1, n) REP(j, 1, n) scanf("%d %d", &ex[i][j], &ey[i][j]);
    REP(i, 1, n) REP(j, 1, n)
        if(ex[i][j] == i && ey[i][j] == j)
            ans[i][j] = 'X', DFS(i, j, i, j); 
    REP(i, 1, n) REP(j, 1, n)
    {
        if(ex[i][j] == -1 && !ans[i][j])
        {
            // 注意,这里两种情况即可,因为 ...-1 的情况在 i=i-1 / j=j-1 的时候枚举到了 
            if(ex[i + 1][j] == -1) 
                ans[i][j] = 'D', ans[i + 1][j] = 'U', DFS(i, j, -1, -1), DFS(i + 1, j, -1, -1);
            if(ex[i][j + 1] == -1) 
                ans[i][j] = 'R', ans[i][j + 1] = 'L', DFS(i, j, -1, -1), DFS(i, j + 1, -1, -1);
        }
    }
    bool invalid = false;
    REP(i, 1, n) REP(j, 1, n) invalid |= !ans[i][j];
    if(invalid) return puts("INVALID") && 0;
    puts("VALID");
    REP(i, 1, n)
    {
        REP(j, 1, n) putchar(ans[i][j]);
        puts("");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/syksykCCC/p/CF1316D.html