CF1100E Andrew and Taxi

2020.11.3

Description

给定一个有向图,现让改变其中某些边的方向,使得其成为一个有向无环图。求一个改变边方向的方案,使得所选边边权的最大值最小。

Solution

首先想到二分,那么小于等于 mid 的边都是可以换向的。对于不可换向的边,如果构成了环,那显然就不行。于是我们二分的下界至少必须使得不可换向的边构成 DAG。再考虑充分性,会发现只要不可换向的边构成 DAG 后,就一定存在方案了。可以这样构造,我们先对 DAG 求拓扑序,那么可换向的边只需要拓扑序小的指向大的。综上,答案就在下界取得。

#include<stdio.h>
#include<string.h>
#define N 200007
#define M 300007

inline int read(){
    int x=0; bool flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}

struct E{
    int next,to;
}e[M];
int head[N],cnt=0;

inline void add(int id,int to){
    e[++cnt]=(E){head[id],to};
    head[id]=cnt;
}

int X[M],Y[M],D[M];
int n,m,dep[N],in[N],sta[N],top=0;
bool check(int lim){
    memset(in,0,sizeof(in));
    memset(head,0,sizeof(head));
    cnt=0,top=0;
    int timer=0;
    for(int i=1;i<=m;i++)
        if(D[i]>lim) add(X[i],Y[i]),in[Y[i]]++;
    for(int i=1;i<=n;i++)
        if(!in[i]) sta[++top]=i,dep[i]=++timer;
    while(top){
        int u=sta[top--];
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(--in[v]) continue;
            sta[++top]=v,dep[v]=++timer;
        }
    }
    for(int i=1;i<=n;i++)
        if(in[i]) return 0;
    return 1;
}

int main(){
//    freopen("pestc.in","r",stdin);
//    freopen("pestc.out","w",stdout);
    n=read(),m=read();
    int l=0,r=0,ans;
    for(int i=1;i<=m;i++){
        X[i]=read(),Y[i]=read(),D[i]=read();
        if(D[i]>r) r=D[i];
    }
    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);
    int ret=0;
    for(int i=1;i<=m;i++)
        if(D[i]<=ans&&dep[X[i]]>dep[Y[i]]) ret++;
    printf(" %d\n",ret);
    for(int i=1;i<=m;i++)
        if(D[i]<=ans&&dep[X[i]]>dep[Y[i]])
            printf("%d ",i);
} 
posted @ 2020-11-04 09:53  Kreap  阅读(94)  评论(0)    收藏  举报