题目大意:给一张图,每条边有一个a到b的代价,同时还有一个b到a的代价,求一个经过所有边所有点的路径使得路径代价最大值最小
首先知道要二分,这样这张图就变成了一些边固定了方向而另一些边两个方向都可以走,这就是一个经典的混合图欧拉回路问题,直接求解即可
混合图欧拉回路知识点讲解戳→这里
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1010
#define M 8010
#define inf 707185547
using namespace std;
void NO(){puts("NIE");exit(0);}
int n,m;
int A[M],B[M],C[M],D[M];
int du[N];
int to[M],nxt[M],pre[N],w[M],cnt;
void ae(int ff,int tt,int ww)
{
cnt++;
to[cnt]=tt;
nxt[cnt]=pre[ff];
w[cnt]=ww;
pre[ff]=cnt;
cnt++;
to[cnt]=ff;
nxt[cnt]=pre[tt];
w[cnt]=0;
pre[tt]=cnt;
}
int S,E;
int q[N],h,t,d[N];
bool bfs()
{
memset(d,0,sizeof(d));
d[S]=1;q[1]=S;
h=t=1;
int i,j,x,y;
while(h<=t)
{
x=q[h];h++;
for(i=pre[x];i;i=nxt[i])
if(w[i])
{
j=to[i];
if(!d[j])
{
d[j]=d[x]+1;
t++;q[t]=j;
}
}
}
if(d[E]) return true;
return false;
}
int dfs(int x,int v)
{
if(x==E||v==0) return v;
int i,j,ret=0;
for(i=pre[x];i;i=nxt[i])
if(w[i])
{
j=to[i];
if(d[j]!=d[x]+1) continue;
int f=dfs(j,min(v,w[i]));
w[i]-=f;
w[i^1]+=f;
v-=f;
ret+=f;
if(v==0) break;
}
if(ret==0) d[x]=-1;
return ret;
}
int dinic()
{
int ret=0;
while(bfs())
ret+=dfs(S,inf);
return ret;
}
int tot;
bool judge(int L)
{
memset(pre,0,sizeof(pre));
cnt=1;
int i,j,x,y;
S=0;E=n+1;
for(i=1;i<=m;i++)
{
if(C[i]>L) return false;
if(D[i]<=L) ae(A[i],B[i],1);
}
for(i=1;i<=n;i++)
{
if(du[i]>0) ae(S,i,du[i]/2);
else if(du[i]<0) ae(i,E,-du[i]/2);
}
if(dinic()==tot/2) return true;
return false;
}
int main()
{
scanf("%d%d",&n,&m);
int i,j,x,y,c,d;
for(i=1;i<=m;i++)
{
scanf("%d%d%d%d",&A[i],&B[i],&C[i],&D[i]);
if(D[i]<C[i])
{
swap(A[i],B[i]);
swap(C[i],D[i]);
}
du[A[i]]++;du[B[i]]--;
}
for(i=1;i<=n;i++)
{
if(du[i]%2!=0) NO();
tot+=abs(du[i])/2;
}
int l=1,r=1000,mid;
while(l<r)
{
mid=(l+r)>>1;
if(judge(mid)) r=mid;
else l=mid+1;
}
printf("%d",l);
}