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

Description:

给出一个n节点m边的有向图,每条边上有一个权值c,现在有一个值为ans,假定仅可以把图中所有的权值小于ans的边自由反向,可以使得整个图无环。求最小的ans,以及相应的反向边有哪些。

Input:

n,m

ui,vi,ci(i=1,2,.....m)

Output:

ans 反向边的数量t

idxi(反向边的编号 i=1..t)

Analysis:

一般遇到这样复杂的优化问题,总是会想到二分搜索,试探假如已经知道了答案,能否较为方便的判断可行性。这一题可以用拓扑排序判断,对于边权大于ans的子图进行拓扑排序,若存在环则ans肯定不行,因为这些边无法改变。若可以进行拓扑排序,就可以的到一个拓扑序,则只要对剩下的边权小于等于ans的边顺着拓扑序的方向就能使得整个图无环.

#define _CRT_SECURE_NO_WARNINGS  
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<sstream>
#include<cmath>
#include<iterator>
#include<bitset>
#include<stdio.h>
#include<unordered_set>
#include<ctime>
#include<cstring>
using namespace std;
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
typedef long long LL;
const int INF = 1 << 30;
const int maxn = 100005;
const int MOD = 1e9+7;
const double eps = 1e-6;
const double pi = acos(-1);

struct Edge {
	int id,to;
	int c;
	Edge(int id,int to,int c):id(id),to(to),c(c){}
	Edge(){}
	bool operator < (const Edge & rhs)const {
		return c < rhs.c;
	}
};

int n, m;
vector<Edge> G[maxn];



void  Topological_sort(int x,vector<int> & order) {
	order.clear();
	vector<int> in_deg(n+1, 0);
	_rep(i,1,n)
		for (auto e : G[i]) {
			if (e.c <= x) continue;
			in_deg[e.to]++;
		}
	_rep(i, 1, n)if (in_deg[i] == 0) {
		order.push_back(i);
	}
	int current = 0;
	while (current < order.size()) {
		int u = order[current++];
		for (auto e : G[u]) {
			if (e.c <= x) continue;
			if (--in_deg[e.to] == 0) {
				order.push_back(e.to);
			}
		}
	}
}

bool Judge(int x,vector<int> & order) {
	order.clear();
	Topological_sort(x,order);
	return order.size() == n;
}

int main()
{
	//freopen("C:\\Users\\admin\\Desktop\\in.txt", "r", stdin);
	//freopen("C:\\Users\\admin\\Desktop\\out.txt", "w", stdout);
	
	ios_base::sync_with_stdio(0);//用这个
	cin.tie(0);                    //就能防止cin超时orz

	while (cin >> n >> m) {
		_rep(i, 1, n) G[i].clear();
		int ans = 0;
		_rep(i,1,m) {
			int u, v, c;
			cin >> u >> v >> c;
			G[u].push_back(Edge(i, v, c));
			ans = max(ans, c);
		}

		vector<int> order;
		int L = 0, R = ans;
		while (L <= R) {
			int mid = L + (R - L) / 2;
			if (Judge(mid,order)) {
				ans = mid;
				R = mid - 1;
			}
			else L = mid + 1;
		}
		Topological_sort(ans, order);
		vector<int> location(n + 1);
		for (int i = 0; i < n; ++i) {
			location[order[i]] = i;
		}
		vector<Edge> p;
		for(int i=1;i<=n;++i)
			for (auto e : G[i]) {
				if (location[e.to] < location[i])
					p.push_back(e);
			}
		cout << ans << " " << p.size() << endl;
		for (auto it : p) cout << it.id << " ";
		cout << endl;
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/tomandjake_/article/details/87435026