Codeforces Round#532(Div.2)E.Andrew and Taxi(二分+トポロジーソート)
2198 ワード
タイトルリンク:http://codeforces.com/contest/1100/problem/E
n個の点を与えて、m条の辺の有向図.各エッジにはエッジ権があり、いくつかのエッジの方向を反転する必要があります.この図をDAGにして、反転されたエッジの最大の重み値を最小化するには、エッジをどのように反転するかを尋ねます.
タイトル構想:試合中に半日見てもこのテーマが最初に何を出力するのか分からなかったので、直接F問題をぶつけました(最後にF問題もぶつけていません.本当の料理QQ)
この問題は最大値の最小化が要求されるため,反転したエッジの最大重み値を二分することを考慮する.有向図にループがあるかどうかを判断するには,トポロジーでソートすることを自然に考えた.二分過程では,辺権がcheck値より大きい辺のみを図に加え(辺権がcheck値以下の後は反転するので,しばらくは気にしない),次にトポロジーソートを行いリングが存在するか否かを判断すればよい.最後にトポロジーソート後の順序関係に基づいて,どの辺が反転するのかを判断し,シナリオ数を出力すればよい.(二分が終わったらもう一度トポロジーソートを走るのを忘れないでください.二分が終わる前に最後に走るトポロジーソートは必ずしも正しいトポロジーソートの順序ではないからです).
具体的な実装はコードを見る:
n個の点を与えて、m条の辺の有向図.各エッジにはエッジ権があり、いくつかのエッジの方向を反転する必要があります.この図をDAGにして、反転されたエッジの最大の重み値を最小化するには、エッジをどのように反転するかを尋ねます.
タイトル構想:試合中に半日見てもこのテーマが最初に何を出力するのか分からなかったので、直接F問題をぶつけました(最後にF問題もぶつけていません.本当の料理QQ)
この問題は最大値の最小化が要求されるため,反転したエッジの最大重み値を二分することを考慮する.有向図にループがあるかどうかを判断するには,トポロジーでソートすることを自然に考えた.二分過程では,辺権がcheck値より大きい辺のみを図に加え(辺権がcheck値以下の後は反転するので,しばらくは気にしない),次にトポロジーソートを行いリングが存在するか否かを判断すればよい.最後にトポロジーソート後の順序関係に基づいて,どの辺が反転するのかを判断し,シナリオ数を出力すればよい.(二分が終わったらもう一度トポロジーソートを走るのを忘れないでください.二分が終わる前に最後に走るトポロジーソートは必ずしも正しいトポロジーソートの順序ではないからです).
具体的な実装はコードを見る:
#include
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define lowbit(x) x&-x
#define clr(a) memset(a,0,sizeof(a))
#define _INF(a) memset(a,0x3f,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define IOS ios::sync_with_stdio(false)
#define fuck(x) cout<G[MX], ans;
int in[MX], pos[MX];
struct edge {
int u, v, w;
} E[MX];
bool check(int cost) {
for (int i = 1; i <= n; i++) G[i].clear(), in[i] = 0;
for (int i = 1; i <= m; i++) {
if (E[i].w <= cost) continue;
G[E[i].u].pb(E[i].v);
in[E[i].v]++;
}
queueq;
for (int i = 1; i <= n; i++) if (in[i] == 0) q.push(i);
int sz = 0;
while (!q.empty()) {
int u = q.front(); q.pop();
pos[u] = ++sz;
for (auto v : G[u]) {
in[v]--;
if (in[v] == 0) q.push(v);
}
}
return sz == n;
}
int main() {
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
#endif
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++)
scanf("%d%d%d", &E[i].u, &E[i].v, &E[i].w);
int l = 0, r = 1e9;
int res = 0;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) {
res = mid;
r = mid - 1;
} else
l = mid + 1;
}
check(res);
for (int i = 1; i <= m; i++)
if (E[i].w <= res && pos[E[i].u] > pos[E[i].v]) ans.pb(i);
printf("%d %d
", res, (int)ans.size());
for (auto x : ans) printf("%d ", x);
printf("
");
return 0;
}