CF1316D Nash Matrix

题目大意

有一个$n \times n$大小的棋盘,棋盘的每个格子上有一个字母(是U,L,R,D,X中之一),其中U表示向上走,D表示向下走,L表示向左走,R表示向右走,X表示走到这个格子就停止。

现在给你$n ^ 2$个坐标$(x_{i,j}, y_{i, j})$表示从$(i, j)$出发能走到的位置(如果无限循环则为$-1$),你需要构造出这个棋盘,或者输出INVALID,$n \leq 10^3$

分析

容易发现一个性质:所有终点相同的点形成独立的联通块

证明很显然,如果$A$的终点是$(x_1, y_1)$,$B$的终点是$(x_2,y_2)$($(x_1,y_1) \not= (x_2, y_2)$),且$A$有边连到$B$的话,那么$A$的终点就不可能是$(x_1, y_1)$,而会是$(x_2,y_2)$与题设矛盾。

那么问题就好解决了

我们首先忽略掉死循环的情况,对于一个(非死循环)联通块,我们可以从这个联通块的终点(即$(i,j)=(x_{i,j},y_{i,j})$的点)向外开始$\texttt{DFS}$,遍历所有与他相邻的点并记录答案。

而对于死循环的情况,显然如果单独的一个点死循环的话肯定是不可能的,这时候输出INVALID即可

否则我们枚举两个相邻的点作为起点,把这两个点连成双元环,然后分别从这两个点开始$\texttt{DFS}$,遍历所有在不经过其中一个点的情况下能走到的所有点并记录答案(详情参见代码)

最后,如果有某一个点没有被遍历到的话则输出INVALID,否则就输出VALID并输出前文处理出的答案

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include <bits/stdc++.h>

#define R register
#define ll long long
#define sum(a, b, mod) (((a) + (b)) % mod)
#define check(x, y) ((x > 0) && (x <= n) && (y > 0) && (y <= n))

const int MaxN = 1e3 + 10;
const char op[] = {'U', 'L', 'D', 'R', 'X'};
const int dx[] = {1, 0, -1, 0}, dy[] = {0, 1, 0, -1};

int n, vis[MaxN][MaxN];
char ans[MaxN][MaxN];
std::vector<std::pair<int, int>> v;
std::pair<int, int> a[MaxN][MaxN];

int nxt(int x, int y, int ex, int ey)
{
for (int i = 0; i <= 3; i++)
if (x + dx[i] == ex && y + dy[i] == ey)
return i;
return -1;
}

inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch > '9' || ch < '0')
{
if (ch == '-')
f = 0;
ch = getchar();
}
while (ch <= '9' && ch >= '0')
x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return f ? x : (-x);
}

void dfs(int x, int y, int Dx) // 正常联通块求解
{
if (ans[x][y]) return;
ans[x][y] = op[Dx];
for (int i = 0; i <= 3; i++)
{
int ex = x + dx[i], ey = y + dy[i];
if (check(ex, ey) && a[ex][ey] == a[x][y])
dfs(ex, ey, i);
}
}

void get(int x, int y) // 求死循环联通块大小
{
vis[x][y] = 1, v.push_back(std::make_pair(x, y));
for (int i = 0; i <= 3; i++)
{
int ex = x + dx[i], ey = y + dy[i];
if (check(ex, ey) && a[ex][ey].first == -1 && a[ex][ey].second == -1 && !vis[ex][ey])
get(ex, ey);
}
}

void Dfs(int x, int y, int banx, int bany, int Dx) // 死循环联通块遍历
{
if (ans[x][y]) return;
ans[x][y] = op[Dx];
for (int i = 0; i <= 3; i++)
{
int ex = x + dx[i], ey = y + dy[i];
if (check(ex, ey) && (a[ex][ey].first == -1 && a[ex][ey].second == -1) && (ex != banx || ey != bany))
Dfs(ex, ey, banx, bany, i);
}
}

int main()
{
n = read();
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
a[i][j].first = read(), a[i][j].second = read();
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (a[i][j].first == i && a[i][j].second == j)
dfs(i, j, 4);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (a[i][j].first == -1 && a[i][j].second == -1 && !vis[i][j])
{
v.clear(), get(i, j);
if (v.size() == 1) return 0 * printf("INVALID");
for (int k = 1; k < v.size(); k++)
{
int x = nxt(v[k - 1].first, v[k - 1].second, v[k].first, v[k].second);
if (~x)
{
Dfs(v[k].first, v[k].second, v[k - 1].first, v[k - 1].second, x);
x = nxt(v[k].first, v[k].second, v[k - 1].first, v[k - 1].second);
Dfs(v[k - 1].first, v[k - 1].second, v[k].first, v[k].second, x);
break;
}
}
}
}
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (!ans[i][j])
return 0 * printf("INVALID");
puts("VALID");
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
putchar(ans[i][j]);
puts("");
}
return 0;
}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×