Codeforces1100 E. Andrew and Taxi(二分+有向图判环,拓扑序)

Posted live4m

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces1100 E. Andrew and Taxi(二分+有向图判环,拓扑序)相关的知识,希望对你有一定的参考价值。

题意:

在这里插入图片描述
在这里插入图片描述

解法:

显然二分答案mid,
将对边权>mid的边判环,如果有环则无解,
如果无环则一定有解,如何构造解?
只用>mid的边进行拓扑排序,记录每个点的拓扑序dfn[i],
对于<=mid的边,选择令拓扑序小的连向拓扑序大的,这样一定不会出现环.

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
int head[maxm],nt[maxm],to[maxm],w[maxm],cnt;
int a[maxm],b[maxm],c[maxm];
int dfn[maxm],idx;
vector<int>temp;
int mark[maxm];
int vis[maxm];
int in[maxm];
int n,m;
int cir;
int ma;
void add(int x,int y,int z){
    cnt++;nt[cnt]=head[x];head[x]=cnt;to[cnt]=y;w[cnt]=z;
}
void dfs(int x){
    if(cir)return ;
    vis[x]=1;
    mark[x]=1;
    for(int i=head[x];i;i=nt[i]){
        int v=to[i];
        if(w[i]<=ma)continue;
        if(!mark[v]){
            dfs(v);
        }else{
            cir=1;
        }
    }
    mark[x]=0;
}
bool check(int mid){
    cir=0;
    for(int i=1;i<=n;i++){
        vis[i]=0;
    }
    //
    ma=mid;
    for(int i=1;i<=n&&!cir;i++){
        if(!vis[i]){
            dfs(i);
        }
    }
    return !cir;
}
void cal(int mid){
    for(int i=1;i<=m;i++){
        if(c[i]>mid){
            in[b[i]]++;
        }
    }
    //拓扑排序
    queue<int>q;
    for(int i=1;i<=n;i++){
        if(!in[i]){
            q.push(i);
        }
    }
    while(q.size()){
        int x=q.front();q.pop();
        dfn[x]=++idx;//拓扑序
        for(int i=head[x];i;i=nt[i]){
            int v=to[i];
            if(w[i]<=mid)continue;
            if(in[v]>0){
                in[v]--;
                if(!in[v]){
                    q.push(v);
                }
            }
        }
    }
    //
    for(int i=1;i<=m;i++){
        if(c[i]<=mid){
            if(dfn[a[i]]>dfn[b[i]]){
                temp.push_back(i);
            }
        }
    }
}
void solve(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&a[i],&b[i],&c[i]);
        add(a[i],b[i],c[i]);
    }
    int l=0,r=1e9;
    int ans=0;
    while(l<=r){
        int mid=(l+r)/2;
        if(check(mid)){
            ans=mid,r=mid-1;
        }else{
            l=mid+1;
        }
    }
    cal(ans);
    printf("%d %d\\n",ans,temp.size());
    for(auto i:temp){
        printf("%d ",i);
    }
}
signed main(){
    solve();
    return 0;
}

以上是关于Codeforces1100 E. Andrew and Taxi(二分+有向图判环,拓扑序)的主要内容,如果未能解决你的问题,请参考以下文章

codeforces 1100E-Andrew and Taxi

CF-1100E Andrew and Taxi

CF 1100E Andrew and Taxi(二分答案)

CF1100E Andrew and Taxi

Codeforces Codeforces Round #484 (Div. 2) E. Billiard

codeforces 598E E. Chocolate Bar(区间dp)