卧薪尝胆,厚积薄发。
Andrew and Taxi
Date: Mon Jan 14 08:18:19 CST 2019 In Category: NoCategory

Description:

给一个图,每条边有权值,把他改造成一个 $DAG$ ,最小化最大边权并输出方案。
$1\leqslant n,m\leqslant 10^5$

Solution:

先二分一个值,然后尝试构造方案,我们可以考虑 $>mid$ 的边,它们的方向显然是固定的,那么如果不能拓扑排序,那显然不合法,否则求出拓扑序,然后按拓扑序连剩下的边即可。

Code:


#include<bits/stdc++.h>
using namespace std;
int n,m;
#define MAXN 100010
struct edges
{
int u,v,w;
}es[MAXN];
struct edge
{
int to,nxt;
}e[MAXN << 1];
int edgenum = 0;
int lin[MAXN] = {0};
int ind[MAXN];
void add(int a,int b)
{
++ind[b];
e[++edgenum] = (edge){b,lin[a]};lin[a] = edgenum;
return;
}
bool vis[MAXN];
int id[MAXN],tot = 0;
bool check(int v)
{
edgenum = 0;
memset(lin,0,sizeof(lin));
memset(ind,0,sizeof(ind));
for(int i = 1;i <= m;++i)
if(es[i].w > v)add(es[i].u,es[i].v);
queue<int> q;
for(int i = 1;i <= n;++i)
if(ind[i] == 0)q.push(i);
memset(vis,false,sizeof(vis));
while(!q.empty())
{
int k = q.front();q.pop();
vis[k] = true;id[k] = ++tot;
for(int i = lin[k];i != 0;i = e[i].nxt)
if((--ind[e[i].to]) == 0)q.push(e[i].to);
}
for(int i = 1;i <= n;++i)if(!vis[i])return false;
return true;
}
int ans[MAXN];
void calc(int k)
{
check(k);
int cnt = 0;
for(int i = 1;i <= m;++i)
{
if(id[es[i].u] > id[es[i].v])ans[++cnt] = i;
}
cout << k << " " << cnt << endl;
for(int i = 1;i <= cnt;++i)printf("%d ",ans[i]);
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= m;++i)
{
scanf("%d%d%d",&es[i].u,&es[i].v,&es[i].w);
}
int l = 0,r = 1000000000,mid;
while(l < r)
{
mid = ((l + r) >> 1);
if(check(mid))r = mid;
else l = mid + 1;
}
calc(l);
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡