074c76fb92802b3aa47016776f481082 _1__page-0001.jpg

 

拓扑排序

题意:给定一个上三角矩阵代表一个数列,其中 aija_{ij} 代表数组元素和 sum[ij]sum[i\cdots j] 的正负,求出一个符合条件的数列。

这是一道构造题,因此只要确定一种可行解即可。

对于一段区间的元素和,自然想到可以理解为两个前缀和的差,而一旦将所有前缀和都求出来了,就可以构造出一组可行解了。

将每一个前缀和 sum[1i]sum[1\cdots i] 视为节点,矩阵中每一个元素视为边,若为正,则代表 sumjsumi>0sum_j-sumi>0 ,即 sumj>sumisum_j>sum_i ,这样一个偏序关系可以用拓扑序来构造出可行解,只要将所有大小关系都表现在边上,最终一定可以找到一个拓扑序列,满足矩阵的所有元素。

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
#include<bits/stdc++.h>
using namespace std;
#define ll long long
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int maxn = 1e4 + 10;
int T;
int n;
char mz[20][20];
vector<int>G[20];
bool vis[20];
int ans[20];
void dfs(int u) {
vis[u] = 1;
for (int v : G[u]) {
if (!vis[v]) {
dfs(v);
}
ans[u] = max(ans[u],ans[v] + 1);
}
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
memset(vis, 0, sizeof(vis));
memset(ans, 0, sizeof(ans));
for (int i = 0; i <= n; i++)G[i].clear();
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j++) {
scanf(" %c", &mz[i][j]);
}
}
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j++) {
if (mz[i][j] == '-')G[i - 1].push_back(j);
else if (mz[i][j] == '+')G[j].push_back(i - 1);
}
}
for (int i = 0; i <= n; i++) {
if (!vis[i])dfs(i);
}
for (int i = 1; i <= n; i++)printf("%d ", ans[i] - ans[i - 1]);
printf("\n");
}
return 0;
}