E. Andrew and Taxi(拓扑序 加边成环问题)

原题: http://codeforces.com/problemset/problem/1100/E

题意:

有n个点,m条有向边。每条边有个花费,当你翻转这条边后所需要花费的价值。翻转多条边的花费为这些边的max。问最小的花费使该图中不存在环。

解析:

首先二分最终答案应该没问题,小于等于答案值的边都可以进行调整。

我做的时候推了一个结论:若原图中没有环,则加一条有向边后,一定存在一种方向使得添加后的图中没有环。

证明:

在这里插入图片描述

也就是说,如果不能改变的那些边不能构成环,则剩下的边一定可以避免构成环(看成一条一条加入)。那么问题就是判环以及剩下的边的朝向。

判环直接拓扑排序即可,判断直到没有入度为0的点后是否还有点。

再来看剩下边的朝向问题。设没有被访问的点x,被访问的点y。对于单单由x构成的边集,按照拓扑序可以保证一不会出现环。对于x与y共同构成的边集,将边的方向朝向y即可。
在这里插入图片描述
那么只需要让被指向的那个y的拓扑序大于其他点即可,所以在遍历的时候,将没有被访问的点在拓扑排序中放在前面即可。

最后按照拓扑序小的指向大的,就可以避免环了。

AC代码:

#include<bits/stdc++.h>
using namespace std;


const int maxn=1e5+5;
int n,m;
int in[maxn],topn[maxn];
vector<int>P[maxn];
struct node {
    int x,y,v,id;
    bool operator<(const node &r)const {
        return v>r.v;
    }
} e[maxn];

bool check(int V) {
    for(int i=1; i<=n; i++)
        in[i]=0,P[i].clear();
    for(int i=1; i<=m&&e[i].v>V; i++) {
        int a=e[i].x,b=e[i].y;
        in[b]++;
        P[a].push_back(b);
    }
    queue<int>Q;
    for(int i=1; i<=n; i++)
        if(!in[i])
            Q.push(i);
    int cnt=0;
    while(!Q.empty()) {
        int id=Q.front();
        Q.pop();
        topn[id]=++cnt;
        for(int i=0; i<P[id].size(); i++) {
            int to=P[id][i];
            in[to]--;
            if(!in[to]) {
                Q.push(to);
            }
        }
    }
    for(int i=1; i<=n; i++)
        if(in[i])
            return 0;
    return 1;
}

int main() {
    scanf("%d%d",&n,&m);

    int l=-1,r=-1;
    for(int i=1; i<=m; i++) {
        scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v);
        e[i].id=i;
        r=max(r,e[i].v+1);
    }
    sort(e+1,e+1+m);
    while(r-l>1) {
        int mid=l+r>>1;
        if(check(mid))
            r=mid;
        else
            l=mid;
    }

    check(r);//最后一步变化l就会出错
    vector<int>ans;
    for(int i=1; i<=m; i++) {
        int a=e[i].x,b=e[i].y;
        if(topn[a]>topn[b])
            ans.push_back(e[i].id);
    }
    printf("%d %d\n",r,ans.size());
    for(int i=0; i<ans.size(); i++)
        printf("%d%c",ans[i],(i==ans.size()-1?'\n':' '));
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/88899949
今日推荐