拓扑排序

CF 1100E Andrew and Taxi 【二分+拓扑排序】

题意:

  • 带权有向图中,求出一个最小值w,存在改变任意权值小于等于w的有向边方向,使得原图变为有向无环图的方案。并输出改变的边数和边们的编号。

思路

  • 二分一个值w,对大于w的边进行拓扑排序,如果无环的话,就减小w
  • 最后改变的边的编号就是top[u]>top[v]边
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pb push_back
typedef vector<int> vi;
const int MAXN=1e5+10;
struct Edge{
    int u,v,w;
}edge[MAXN];
int n,m,top[MAXN],indec[MAXN];
vi G[MAXN];
bool check(int mid){
    int cnt=0;
    rep(i,1,n){
        G[i].clear();
        indec[i]=0;
    }
    rep(i,1,m){
        if(edge[i].w>mid){
            G[edge[i].u].pb(edge[i].v);
            indec[edge[i].v]++;
        }
    }
    queue<int> que;
    rep(i,1,n){
        if(indec[i]==0){
            que.push(i);
        }
    }
    while(!que.empty()){
        int u=que.front();
        que.pop();
        top[u]=++cnt;
        for(auto v:G[u]){
            indec[v]--;
            if(indec[v]==0){
                que.push(v);
            }
        }
    }
    return cnt==n;
}
int main(){
    scanf("%d%d",&n,&m);
    rep(i,1,m){
        scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
    }
    int l=0,r=1e9+10,ans=r;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid)){
            ans=mid;
            r=mid-1;
        }else{
            l=mid+1;
        }
    }
    printf("%d ",ans);
    check(ans);
    vi res;
    rep(i,1,m){
        int u=edge[i].u,v=edge[i].v,w=edge[i].w;
        if(w<=ans&&top[u]>top[v]){
            res.pb(i);
        }
    }
    printf("%d\n",res.size());
    for(auto x:res){
        printf("%d ",x);
    }
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值