Valuable Paper

Valuable Paper

Created by LXC on Tue Mar 12 14:17:24 2024

https://codeforces.com/problemset/problem/1423/B

ranting: 1900

tag: binary search, flows, graph matchings, graphs

problem

大流感来袭,世界上最缺乏的物资是厕纸。

有N个厕纸工厂和N个机场,由于某些原因,每个工厂只能运往1个机场,每个机场只能从1个工厂运货。

现在有M条路能修,每条路都有一个需要的时间di。

现在要找N条路沟通这N对工厂机场,使得这些路同时开始修,最终修好的时间最短。

solution

二分答案+二分图最大匹配

假设答案是x,那么对于所有是时间小于等于x的边建立二分图,然后判断匹配的最大边数是否为n,若为n则答案不大于x,否则答案大于x。

使用增广路算法求二分图最大匹配的时间复杂度为$O(VE)$

code

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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141

#include <bits/stdc++.h>
#define SINGLE_INPUT
#define ll long long
#define ull unsigned long long
#define N 500005
#define MOD 998244353
using namespace std;

template<class t,class u> ostream& operator<<(ostream& os,const pair<t,u>& p) {
return os<<'['<<p.first<<", "<<p.second<<']';
}
template<class t> ostream& operator<<(ostream& os,const vector<t>& v) {
os<<'['; int s = 1;
for(auto e:v) { if (s) s = 0; else os << ", "; os << e; }
return os<<']';
}
template<class t,class u> ostream& operator<<(ostream& os,const map<t,u>& mp){
os<<'{'; int s = 1;
for(auto [x,y]:mp) { if (s) s = 0; else os << ", "; os<<x<<": "<<y; }
return os<<'}';
}

struct Rode {
int u, v, d;
Rode(int u, int v, int d):u(u),v(v),d(d) {}
bool operator<(const Rode& o) {
return d > o.d;
}
};

struct augment_path {
vector<vector<int> > g;
vector<int> pa; // 匹配
vector<int> pb;
vector<int> vis; // 访问
int n, m; // 两个点集中的顶点数量
int dfn; // 时间戳记
int res; // 匹配数

augment_path(int _n, int _m) : n(_n), m(_m) {
assert(0 <= n && 0 <= m);
pa = vector<int>(n, -1);
pb = vector<int>(m, -1);
vis = vector<int>(n);
g.resize(n);
res = 0;
dfn = 0;
}

void add(int from, int to) {
assert(0 <= from && from < n && 0 <= to && to < m);
g[from].push_back(to);
}

bool dfs(int v) {
vis[v] = dfn;
for (int u : g[v]) {
if (pb[u] == -1) {
pb[u] = v;
pa[v] = u;
return true;
}
}
for (int u : g[v]) {
if (vis[pb[u]] != dfn && dfs(pb[u])) {
pa[v] = u;
pb[u] = v;
return true;
}
}
return false;
}

int solve() {
while (true) {
dfn++;
int cnt = 0;
for (int i = 0; i < n; i++) {
if (pa[i] == -1 && dfs(i)) {
cnt++;
}
}
if (cnt == 0) {
break;
}
res += cnt;
}
return res;
}
};

void sol() {
int n, m;
cin >> n >> m;
vector<Rode> rd;
for (int i=0; i<m; i++) {
int u, v, d;
cin >> u >> v >> d;
rd.emplace_back(--u, --v, d);
}
sort(rd.begin(), rd.end());
// cout << deg << endl;
ll l = 0, r = 1e9+7;
while (l<r) {
ll m = l+r>>1;
// cout << l << " " << r << " " << m << endl;
augment_path ap(n, n);
for (auto [u,v,d]:rd) {
if (d<=m) ap.add(u, v);
}
int ans = ap.solve();
if (ans == n) {
r = m;
} else {
l = m+1;
}
}
if (r == 1e9+7) cout << "-1\n";
else cout << r << "\n";


}

int main() {
cout << setprecision(15) << fixed;
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifndef SINGLE_INPUT
int t;
cin >> t;
while (t--) {
sol();
}
#else
sol();
#endif
return 0;
}