标签
拓扑排序好题
题目描述
看下面的五张 9 x 8 的图像 (别说有点像某的世界的传送门):
........ ........ ........ ........ .CCC....
EEEEEE.. ........ ........ ..BBBB.. .C.C....
E....E.. DDDDDD.. ........ ..B..B.. .C.C....
E....E.. D....D.. ........ ..B..B.. .CCC....
E....E.. D....D.. ....AAAA ..B..B.. ........
E....E.. D....D.. ....A..A ..BBBB.. ........
E....E.. DDDDDD.. ....A..A ........ ........
E....E.. ........ ....AAAA ........ ........
EEEEEE.. ........ ........ ........ ........
1 2 3 4 5
现在,把这些图像按照 1—5 的编号从下到上重叠,第 1 张在最下面,第 5 张在最顶端。如果一张图像覆盖了另外一张图像,那么底下的图像的一部分就变得不可见了。我们得到下面的图像:
.CCC....
ECBCBB..
DCBCDB..
DCCC.B..
D.B.ABAA
D.BBBB.A
DDDDAD.A
E...AAAA
EEEEEE..
对于这样一张图像,计算构成这张图像的矩形图像从底部到顶端堆叠的顺序。
下面是这道题目的规则:
矩形的边的宽度为 1 ,每条边的长度都不小于 3 。
矩形的每条边中,至少有一部分是可见的。注意,一个角同时属于两条边。
矩形用大写字母表示,并且每个矩形的表示符号都不相同。
AC艰难历程
-
44
44
44 分:打了一个普普通通的宽搜(拓扑)。
- 错误原因:
眼瞎没有看到题目中按字典序输出所有拓扑序……
- 错误原因:
-
100
100
100 分:
突然眼不瞎了把普普通通的宽搜改成了普普通通的深搜
就说我错的冤不冤吧。
题解
思路
且看下面这张图:
........
ECBCBB..
D....B..
D....B..
D....B..
D....B..
D....D..
E....A..
EEEEEE..
这些是在 E 这个框框上的字符,
表明这些字符的优先级都在 E 之上;
我们只需要在建 DAG 图时将 E 指向这些节点即可;
最后用 DFS 求出这个 DAG 图的所有拓扑序即可。
证明
略
代码
#include <bits/stdc++.h>
#define ios \
ios::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0)
// #pragma GCC Typetimize(2)
#define int long long
#define pll pair<ll, ll>
#define pii pair<int, int>
#define il inline
#define p_q priority_queue
#define u_m unordered_map
#define r_g register
using namespace std;
int n, m;
char a[100][100];
vector<int> G[1000];
class Square {//一个框框,保存左上节点和右下节点
public:
int maxX, maxY;
int minX, minY;
Square() {
minX = minY = INT_MAX;
}
};
Square sq[1000];
int In[1000];
bool vis[1000];
p_q<string, vector<string>, greater<string>> Ans;
vector<char> ans;
void dfs(string tans) {//dfs求拓扑序
if (tans.size() == ans.size()) {
Ans.push(tans);
return ;
}
for (int i = 0; i < ans.size(); i++) {
if (In[ans[i]] == 0) {
tans.push_back(ans[i]);
for (auto x : G[ans[i]]) {
In[x]--;
}
dfs(tans);
tans.pop_back();
for (auto x : G[ans[i]]) {
In[x]++;
}
}
}
}
signed main() {
memset(In, 0xff, sizeof(In));
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
}
}
for (int i = 1; i <= n; i++) {//获取框框边界
for (int j = 1; j <= m; j++) {
sq[a[i][j]].minX = min(sq[a[i][j]].minX, i);
sq[a[i][j]].maxX = max(sq[a[i][j]].maxX, i);
sq[a[i][j]].minY = min(sq[a[i][j]].minY, j);
sq[a[i][j]].maxY = max(sq[a[i][j]].maxY, j);
}
}
for (char c = 'A'; c <= 'Z'; c++) {//建图,有些冗余,凑活着看扒
memset(vis, true, sizeof(vis));
if (!sq[c].maxX)
continue;
ans.push_back(c);
for (int i = sq[c].minX; i <= sq[c].maxX; i++) {
if (vis[a[i][sq[c].minY]]) {
In[a[i][sq[c].minY]] += vis[a[i][sq[c].minY]];
vis[a[i][sq[c].minY]] = false;
G[c].push_back(a[i][sq[c].minY]);
}
if (vis[a[i][sq[c].maxY]]) {
In[a[i][sq[c].maxY]] += vis[a[i][sq[c].maxY]];
vis[a[i][sq[c].maxY]] = false;
G[c].push_back(a[i][sq[c].maxY]);
}
}
for (int i = sq[c].minY; i <= sq[c].maxY; i++) {
if (vis[a[sq[c].minX][i]]) {
In[a[sq[c].minX][i]] += vis[a[sq[c].minX][i]];
vis[a[sq[c].minX][i]] = false;
G[c].push_back(a[sq[c].minX][i]);
}
if (vis[a[sq[c].maxX][i]]) {
In[a[sq[c].maxX][i]] += vis[a[sq[c].maxX][i]];
vis[a[sq[c].maxX][i]] = false;
G[c].push_back(a[sq[c].maxX][i]);
}
}
}
dfs("");
while (Ans.size()) {//输出
cout << Ans.top() << "\n";
Ans.pop();
}
return 0;
}