CF1100E Andrew and Taxi
2020.11.3
Link
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);
}

浙公网安备 33010602011771号