欧拉回路与欧拉路径
一笔画条件:起点边数 = 奇数,终点边数 = 奇数,中间点边数= 偶数。
欧拉回路:终点就是起点
一、无向图
1 存在欧拉路径的充要条件 : 度数为奇数的点只能有0或2个
2 存在欧拉回路的充要条件 : 度数为奇数的点只能有0个
二、有向图
1 存在欧拉路径的充要条件 : 要么所有点的出度均==入度;
要么除了两个点之外,其余所有点的出度==入度 剩余的两个点:一个满足出度-入度==1(起点) 一个满足入度-出度==1(终点)
2 存在欧拉回路的充要条件 : 所有点的出度均等于入度
1123. 铲雪车
题意:在双向道铲雪,每条边都要铲两次,求最少铲雪时间。
双向道说明出度=入度,必然存在欧拉回路,直接求路径长度乘 2 然后计算时间即可。
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
|
#include <bits/stdc++.h>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
typedef long long ll;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
int s, t, u, v;
double sum;
int main()
{
cin >> s >> t;
while (cin >> s >> t >> u >> v) {
double dx = s - u;
double dy = t - v;
sum += sqrt(dx * dx + dy * dy) * 2;
}
int minutes = round(sum / 1000 / 20 * 60);
int hours = minutes / 60;
minutes %= 60;
printf("%d:%02d\n", hours, minutes);
return 0;
}
|
拓扑排序
1191. 家谱树
题意:模板题,求 $n$ 个点有向图的拓扑序。
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 debug(x) cout << #x << " is " << x << endl
typedef long long ll;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const int N = 105, M = N * N / 2;
int n, tot, cnt;
int ver[M], nxt[M], head[N], ind[N];
int a[N];
void add(int x, int y) {
ver[++tot] = y; nxt[tot] = head[x]; head[x] = tot;
}
void topsort() {
queue<int> q;
for (int i = 1; i <= n; ++i)
if (!ind[i]) q.push(i);
while (!q.empty()) {
int x = q.front(); q.pop();
a[++cnt] = x;
for (int i = head[x]; i; i = nxt[i]) {
int y = ver[i];
if (--ind[y] == 0) q.push(y);
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
int x;
for (int i = 1; i <= n; ++i) {
while (cin >> x, x) {
add(i, x);
ind[x]++;
}
}
topsort();
for (int i = 1; i <= n; ++i) cout << a[i] << " \n"[i == n];
return 0;
}
|
1192. 奖金
题意:$n(1\le x\le10000)$ 个员工,$m(1\le m\le20000)$ 个要求,每个要求 a b
表示 a 员工比 b 员工奖金高,每位员工奖金最少为 $100$ 元。
差分约束系统,边权为正,拓扑序求最长路。
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
|
#include <bits/stdc++.h>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
typedef long long ll;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const int N = 1e4 + 5, M = 2e4 + 5;
int n, m, tot, cnt;
int ver[M], nxt[M], head[N];
int ind[N], a[N], pri[N];
void add(int x, int y) {
ver[++tot] = y, nxt[tot] = head[x], head[x] = tot;
}
int topsort() {
queue<int> q;
for (int i = 1; i <= n; ++i)
if (!ind[i]) q.push(i);
while (!q.empty()) {
int x = q.front(); q.pop();
a[++cnt] = x;
for (int i = head[x]; i; i = nxt[i]) {
int y = ver[i];
if (--ind[y] == 0) q.push(y);
}
}
return cnt == n;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
int x, y;
for (int i = 1; i <= m; ++i) {
cin >> x >> y;
add(y, x);
ind[x]++;
}
if (!topsort()) { cout << "Poor Xed\n"; exit(0); }
for (int i = 1; i <= n; ++i) pri[i] = 100;
for (int i = 1; i <= n; ++i) {
int x = a[i];
for (int j = head[x]; j; j = nxt[j]) {
int y = ver[j];
pri[y] = max(pri[y], pri[x] + 1);
}
}
int ans = 0;
for (int i = 1; i <= n; ++i) ans += pri[i];
cout << ans << '\n';
return 0;
}
|
AcWing 164. 可达性统计
题意:$n$ 个点 $m$ 条边的有向无环图($1\le n,m\le30000$),统计从每个点出发能到达的点的数量。
利用拓扑序的逆序计算,每个点后继结点答案并集+1为该点答案,用bitset状态压缩求解,f[x]
第 i 位为 1 表示从 x 能到 i,最后求每个 x 中 1 的数量。
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
|
#include <bits/stdc++.h>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
typedef long long ll;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const int N = 3e4 + 5, M = N;
int n, m, tot, cnt;
int ver[M], nxt[M], head[N];
int ind[N], a[N];
bitset<N> f[N];
void add(int x, int y) {
ver[++tot] = y, nxt[tot] = head[x], head[x] = tot;
}
void topsort() {
queue<int> q;
for (int i = 1; i <= n; ++i)
if (!ind[i]) q.push(i);
while (!q.empty()) {
int x = q.front(); q.pop();
a[++cnt] = x;
for (int i = head[x]; i; i = nxt[i]) {
int y = ver[i];
if (--ind[y] == 0) q.push(y);
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
int x, y;
for (int i = 1; i <= m; ++i) {
cin >> x >> y;
add(x, y);
ind[y]++;
}
topsort();
for (int i = n; i; --i) {
int x = a[i];
f[x][x] = 1;
for (int j = head[x]; j; j = nxt[j]) {
int y = ver[j];
f[x] |= f[y];
}
}
for (int i = 1; i <= n; ++i)
cout << f[i].count() << '\n';
return 0;
}
|
456. 车站分级
题意:$n$ 个火车站,每个火车站一个级别,最低为 1,如果火车站经过 $x$,始发站、终点站之间所有大于等于 x 的火车站必须停靠,$m$ 趟列车,第 $i$ 趟 $s_i$ 个停靠站,求 $n$ 个火车站最少划分的级别数。
差分约束,未停靠的一定小于停靠的,最坏 $1000$ 个火车站和列车,每趟 $500$ 个停靠,有 $500\times500\times1000=2.5\times10^8$ 条边,考虑两个集合中的点连虚拟点来优化。
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
|
#include <bits/stdc++.h>
using namespace std;
#define debug(x) cout << #x << " is " << x << endl
typedef long long ll;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const int N = 2005, M = 1e6 + 5;
int n, m, tot, cnt;
int ver[M], edge[M], nxt[M], head[N];
int ind[N], a[N], vis[N], level[N];
void add(int x, int y, int z) {
ver[++tot] = y, edge[tot] = z, nxt[tot] = head[x], head[x] = tot;
ind[y]++;
}
void topsort() {
queue<int> q;
for (int i = 1; i <= n + m; ++i)
if (!ind[i]) q.push(i);
while (!q.empty()) {
int x = q.front(); q.pop();
a[++cnt] = x;
for (int i = head[x]; i; i = nxt[i]) {
int y = ver[i];
if (--ind[y] == 0) q.push(y);
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
int k, x, st, ed;
for (int i = 1; i <= m; ++i) {
memset(vis, 0, sizeof(vis));
cin >> k;
for (int j = 1; j <= k; ++j) {
cin >> x;
if (j == 1) st = x;
else if (j == k) ed = x;
vis[x] = 1;
}
int tmp = n + i;
for (int j = st; j <= ed; ++j) {
if (!vis[j]) add(j, tmp, 0);
else add(tmp, j, 1);
}
}
topsort();
for (int i = 1; i <= n; ++i) level[i] = 1;
for (int i = 1; i <= n + m; ++i) {
int x = a[i];
for (int j = head[x]; j; j = nxt[j]) {
int y = ver[j];
level[y] = max(level[y], level[x] + edge[j]);
}
}
int ans = 0;
for (int i = 1; i <= n; ++i) ans = max(ans, level[i]);
cout << ans << '\n';
return 0;
}
|