Description
YYD为了减肥,他来到了瘦海,这是一个巨大的海,海中有n个小岛,小岛之间有m座桥连接,两个小岛之间不会有两座桥,并且从一个小岛可以到另外任意一个小岛。现在YYD想骑单车从小岛1出发,骑过每一座桥,到达每一个小岛,然后回到小岛1。霸中同学为了让YYD减肥成功,召唤了大风,由于是海上,风变得十分大,经过每一座桥都有不可避免的风阻碍YYD,YYD十分ddt,于是用泡芙贿赂了你,希望你能帮他找出一条承受的最大风力最小的路线。
Input
输入:第一行为两个用空格隔开的整数n(2<=n<=1000),m(1<=m<=2000),接下来读入m行由空格隔开的4个整数a,b(1<=a,b<=n,a<>b),c,d(1<=c,d<=1000),表示第i+1行第i座桥连接小岛a和b,从a到b承受的风力为c,从b到a承受的风力为d。
Output
输出:如果无法完成减肥计划,则输出NIE,否则第一行输出承受风力的最大值(要使它最小)
最大值最小,想到二分。
那么接下来就是check的问题,check的主要作用就是判断这个由
≤
\leq
≤mid的边组成的图是否能构成欧拉回路。
因为本题要求的路线实际上是一个欧拉回路,那么我们可以在每个点的入度出度上做文章。
对于一个点u,因为u在欧拉回路中,
i
n
[
u
]
=
=
o
u
t
[
u
]
in[u]==out[u]
in[u]==out[u],然而,在这个残余的图中,有些点的in,out是不相同的,但是这个图还是能构成欧拉回路,为什么?
因为在这个图中,有些的边是无向边,你在一种情况下in,out不相等是因为你取得是无向边的一种情况。
显然给一条无向边选方向是不会改变边两端的点的in-out=sum[u]的奇偶性(每次只会+2或-2),所以如果有一点sum值为奇数,显然不成立。
其次,如果有点不连通,也是显然不成立的。
那么我们可以想到一个建图:
s连接sum为正的点,流量为sum(表示多的流量)
sum为负的点连接t,流量为-sum(表示缺少的流量)
之间有无向边的两点连一条流量2的边(表示转化一次的流量)
满流意味着是欧拉回路。
int getfa(int x)//并查集判联通
{
if(fa[x]==x)
{
return x;
}
return getfa(fa[x]);
}
bool check(int mid)//判断欧拉回路
{
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(head,0,sizeof(head));
memset(vis,0,sizeof(vis));
cnt=1;
for(int i=1;i<=n;i++)
{
fa[i]=i;
}
for(int i=1;i<=m;i++)
{
if(zz[i]>mid&&hh[i]>mid)
{
return 0;
}
if(zz[i]<=mid)
{
in[yy[i]]++;
out[xx[i]]++;
vis[i]=1;
fa[getfa(xx[i])]=getfa(yy[i]);
if(hh[i]<=mid)
{
vis[i]=3;
}
}else{
in[xx[i]]++;
out[yy[i]]++;
vis[i]=2;
fa[getfa(yy[i])]=getfa(xx[i]);
}
}
for(int i=1;i<=n;i++)
{
if(abs(in[i]-out[i])&1)
{
return 0;
}
if((i!=n)&&(getfa(i)!=getfa(i+1)))
{
return 0;
}
}
s=0;
t=n+1;
for(int i=1;i<=m;i++)
{
if(vis[i]==3)
{
adde(yy[i],xx[i],1);
adde(xx[i],yy[i],0);
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
if(in[i]==out[i])
{
continue;
}
if(in[i]>out[i])
{
adde(s,i,(in[i]-out[i])/2);
adde(i,s,0);
}else{
adde(i,t,(out[i]-in[i])/2);
adde(t,i,0);
ans+=(out[i]-in[i])/2;
}
}
dinic();
return ans==maxnf;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d%d",&xx[i],&yy[i],&zz[i],&hh[i]);
maxn=max(maxn,max(zz[i],hh[i]));
}
int l=1,r=maxn+1;//二分
while(l<r)
{
int mid=(l+r)>>1;
if(check(mid))
{
r=mid;
}else{
l=mid+1;
}
}
if(l>maxn)
{
puts("NIE");
}else{
printf("%d\n",l);
}
return 0;
}