Codeforces Round #532 (Div. 2) E. Andrew and Taxi(拓扑排序+二分)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/bnubeginner/article/details/86544873

先呈上原题链接[Codeforces Round #532 (Div. 2) E. Andrew and Taxi]
题意:
一个n个顶点m条边的有向图,每条边都有权值(即修改这条边方向所要付出的代价)

目的:改变部分边的方向,使图无环。

要求:寻找一种方案使改变的边的权值的最大值最小。输出权值和需要改变方向的边的编号。

思路:
先二分答案:

答案(ans)范围在0与这个图的最大权值之间,所以直接(在L和R之间)二分寻找答案。每给定一个值m=(L+R)/2
若所有边权大于该值的边构成的图存在环路,也就是说存在一些边权大于m的边是必须要改变方向的,则ans一定大于m,ans一定落在m到R区间内。
若所有边权大于该值的边构成的图不存在环路,ans一定落在L到m区间内。

第二步寻找需要改变的方向的边。这个时候就需要用到拓扑排序了。(在拓扑排序中每个点都有一个从小到大都有一个权值,若点A的拓扑序在点B前面那么点A的权值也就比B小。)
我们遍历每一条边,如果有向边是A–>B,但是A的权值却比B大,那么这条边的方向就需要改变。因为A的拓扑序在B的后面但是这条边的方向确实A到B,所以必须改为B到A。

因为拓扑排序的结果本来就不唯一,且题目也没有要求我们改变方向的边的条数要最少,所以上面的操作只要我们保证改变某些边方向后,图是无环的,而并没有保证改变的边的个数最少。

坑点:
好像也没什么坑点,好好写就能过吧。

good luck and have fun!!!
附上代码:

#include<bits/stdc++.h>
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define test(flag,value) cout<<flag<<":"<<(value)<<endl
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int INF=0x3f3f3f3f;
const int MOD=1e9+7;
const int MAXN=2e5+5;
const double PI=acos(-1);
int n,m;
int u[MAXN],v[MAXN],w[MAXN];
int level[MAXN],in[MAXN];
vector<int> G[MAXN];
int path[MAXN];
queue<int> Q;
bool check(int val)
{
	while(!Q.empty())Q.pop();
	int cnt=0;
	mem(in,0);
	mem(G,0);
	for(int i=1;i<=m;i++)
		if(w[i]>val)
			G[u[i]].pb(v[i]),in[v[i]]++;
	for(int i=1;i<=n;i++)if(!in[i]) Q.push(i),level[i]=cnt++;
	while(!Q.empty())
	{
		int tmp=Q.front();Q.pop();
		for(int i=0;i<(int)G[tmp].size();i++)
		{
			int x=G[tmp][i];
			in[x]--;
			if(!in[x]) Q.push(x),level[x]=cnt++;
		}
	}
	for(int i=1;i<=n;i++) if(in[i]) return false;
	return true;
}
int main(void)
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
		scanf("%d%d%d",u+i,v+i,w+i);
	int l=0,r=1e9+5,mid;
	while(l<r)
	{
		mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	int ans=l;
	check(ans);
	int cnt=0;
	for(int i=1;i<=m;i++)
		if(level[u[i]]>level[v[i]])
			path[cnt++]=i;
	printf("%d %d\n", ans,cnt);
	for(int i=0;i<cnt;i++)
		printf("%d ", path[i]);
}

猜你喜欢

转载自blog.csdn.net/bnubeginner/article/details/86544873