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

 

题目链接:https://codeforces.com/contest/1100/problem/E

       题意是n个点,m条有向边,每条边都有一个权值,将某些边变向,使得图变成一个无环图,要使所有变向的边中权值最大的最小,输出这个最大的最小值和变向的边。

       大致思路是二分答案,然后用拓扑排序去判断是否存在环。具体的操作是我们把每次枚举的mid作为建边的依据,把大于mid的边建起来,因为答案是变向的边的最大值,所以比mid大的边都是不用变向的边,所以将他们建好边以后判断一下图是否是无环图(入队个数等于n就是无环图),如果不是无环图的话,说明这些边有些还需要变向,那么就扩大mid的值。如果这个图是一个无环图的话,就更新ans数组,更新的过程是它的权值要小于等于mid,然后按它的拓扑顺序进行变向,并将mid缩小去找更小的答案。有一个讲的不错的文章,对于更新ans数组的过程有详细的解释,可以去看看:https://www.geeksforgeeks.org/


AC代码:

#include 
#define maxn 100005
using namespace std;
struct Node{
  int x, y, w;
}Edge[maxn];
int pre[maxn], dep[maxn], pos[maxn];
vector ans;
int n,m;

bool Check(int xx){
  vector v[maxn];
  memset(dep, 0, sizeof(dep));
  for(int i=1;i<=m;i++){
    if(Edge[i].w > xx){
      v[Edge[i].x].push_back(Edge[i].y);
      dep[Edge[i].y] ++;
    }
  }
  queue q;
  int cnt = 0, yy = 0;
  for(int i=1;i<=n;i++) if(dep[i] == 0) q.push(i), pos[i] = ++cnt, yy++;
  while(!q.empty()){
    int u = q.front();
    q.pop();
    for(int i=0;i> 1;
    if(Check(mid)) r = mid - 1, xx = mid;
    else l = mid + 1;
  }
  // Check(xx);     我觉得这里不需要再更新一次ans数组了 因为xx和ans是同步更新的
  printf("%d %d\n",xx, ans.size());
  for(int i=0;i

 

你可能感兴趣的:(CodeForces,ACM_二分,ACM_拓扑排序)