简单拓扑排序的学习笔记
简单拓扑排序的学习。
拓扑排序是给有向无环图的每一个节点分级。每个节点指向的节点的等级值一定大于该节点的等级值。
bfs实现。复杂度 \(O(e+v)\)
void topo_sort()
{
queue<int> q;
for (int i = 1; i <= n; i++)
if (rd[i] == 0)
{
q.push(i);
ans[i] = 1;
}
while (!q.empty())
{
int now = q.front();
q.pop();
for (int i = 0; i < e[now].size(); i++)
{
rd[e[now][i]]--;
if (rd[e[now][i]] == 0)
q.push(e[now][i]);
ans[e[now][i]] = max(ans[e[now][i]], ans[now] + 1);
}
}
}
洛谷P1347 排序
题意,给定若干个偏序,求全序。同时判断是否有矛盾。
有矛盾就是出现环了,也就是有节点无法入队。
没法排序就是有两个节点等级值相同。
\(n = 26\) 暴力出奇迹就完事了,加一条边拓扑排序一次。
甚至可以用邻接矩阵233。
这代码写的挺破的,当时初学。
#include<bits/stdc++.h>
using namespace std;
int a[100][100], f[100], rd[100], ans[100];
int n, m;
bool topo_sort(int &tot)
{
tot = 0;
int cnt = 0;
queue<int> q;
memset(f, 0, sizeof(f));
memset(rd, 0, sizeof(rd));
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (a[i][j])
rd[j]++;
for (int i = 0; i < n; i++)
if (rd[i] == 0)
{
q.push(i);
f[i] = 1;
ans[cnt++] = i;
tot++;
}
while (!q.empty())
{
int now = q.front();
q.pop();
for (int i = 0; i < n; i++)
if (a[now][i])
{
rd[i]--;
if (rd[i] == 0)
{
q.push(i);
tot++;
ans[cnt++] = i;
}
f[i] = max(f[now] + 1, f[i]);
}
}
return tot == n;
}
int main()
{
ios::sync_with_stdio(false);
cin >> n >> m;
char x, y, ch;
int tot = 0, type = 0;
for (int i = 0; i < m; i++)
{
cin >> x >> ch >> y;
a[x - 'A'][y - 'A'] = 1;
if (topo_sort(tot))
{
bool ok = true;
for (int j = 0; j < n; j++)
for (int k = 0; k < n; k++)
if (j != k && f[k] == f[j])
{
ok = false;
break;
}
if (ok)
{
type = i + 1;
break;
}
}
else
{
cout << "Inconsistency found after " << i + 1 << " relations." << endl;
return 0;
}
}
if (type == 0)
{
cout << "Sorted sequence cannot be determined." << endl;
return 0;
}
else
{
cout << "Sorted sequence determined after " << type << " relations: ";
for (int i = 0; i < n; i++)
cout << char(ans[i] + 'A');
cout << "." << endl;
return 0;
}
}
洛谷P1137 旅行计划
有一个DAG,一个起点,求走到每个点最多能经过几个点。
简单dp的思想,其实每一个点的答案就是它的等级值。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
vector<int> e[maxn];
int ans[maxn];
int rd[maxn];
int n, m, x, y;
void topo_sort()
{
queue<int> q;
for (int i = 1; i <= n; i++)
if (rd[i] == 0)
{
q.push(i);
ans[i] = 1;
}
while (!q.empty())
{
int now = q.front();
q.pop();
for (int i = 0; i < e[now].size(); i++)
{
rd[e[now][i]]--;
if (rd[e[now][i]] == 0)
q.push(e[now][i]);
ans[e[now][i]] = max(ans[e[now][i]], ans[now] + 1);
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++)
{
scanf("%d%d", &x, &y);
e[x].push_back(y);
rd[y]++;
}
topo_sort();
for (int i = 1; i <= n; i++)
printf("%d\n", ans[i]);
return 0;
}
NOIP2003提高组 神经网络
较复杂状态转移。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 110;
struct node
{
int v, nxt;
};
vector<node> e[maxn];
int n, p, x, y, w, u[maxn], rd[maxn], cd[maxn], c[maxn];
void topo_sort()
{
queue<int> q;
for (int i = 1; i <= n; i++)
if (c[i] > 0)
q.push(i);
else
c[i] -= u[i]; // 提前处理一下
while (!q.empty())
{
int now = q.front();
q.pop();
if (c[now] <= 0)
continue;
for (int i = 0; i < e[now].size(); i++)
{
c[e[now][i].nxt] += e[now][i].v * c[now]; // 状态转移
rd[e[now][i].nxt]--;
if (rd[e[now][i].nxt] == 0)
q.push(e[now][i].nxt);
}
}
}
int main()
{
scanf("%d%d", &n, &p);
for (int i = 1; i <= n; i++)
scanf("%d%d", &c[i], &u[i]);
for (int i = 0; i < p; i++)
{
scanf("%d%d%d", &x, &y, &w);
e[x].push_back({ w, y });
rd[y]++;
cd[x]++;
}
topo_sort();
bool flag = 1;
for (int i = 1; i <= n; i++)
if (cd[i] == 0 && c[i] > 0)
printf("%d %d\n", i, c[i]);
for (int i = 1; i <= n; i++)
if (cd[i] == 0 && c[i] != 0)
flag = 0;
if (flag)
puts("NULL");
return 0;
}
NOIP2013普及组 车站分级
对于某一辆车,停的站一定比没停的等级高,如此建图。
答案就是最大的等级值。
一堆诡异的细节处理,蛋疼。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1100;
int n, m, a[maxn][maxn], s[maxn];
vector<int> stations[maxn];
int rd[maxn], e[maxn][maxn];
int ans[maxn];
void topo_sort()
{
queue<int> q;
for (int i = 1; i <= n; i++)
if (rd[i] == 0)
{
q.push(i);
ans[i] = 1;
}
while (!q.empty())
{
int now = q.front();
q.pop();
for (int i = 1; i <= n; i++)
{
if (e[now][i])
{
rd[i]--;
if (rd[i] == 0)
{
q.push(i);
ans[i] = max(ans[i], ans[now] + 1);
}
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
int x;
for (int i = 1; i <= m; i++)
{
scanf("%d", &s[i]);
for (int j = 0; j < s[i]; j++)
{
scanf("%d", &x);
a[i][x] = 1;
stations[i].push_back(x);
}
for (int j = stations[i][0]; j <= stations[i][s[i] - 1]; j++)
{
if (a[i][j] == 0)
for (int k = stations[i][0]; k <= stations[i][s[i] - 1]; k++)
if (a[i][k] == 1)
e[j][k] = 1;
}
}
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (e[i][j])
rd[j]++;
topo_sort();
int qwq = 0;
for (int i = 1; i <= n; i++)
qwq = max(qwq, ans[i]);
printf("%d\n", qwq);
return 0;
}