【BZOJ2095】【POI2010】Bridge 網絡流
阿新 • • 發佈:2018-03-05
則無 cti rac ctime def urn freopen cpp 奇數 。
題目大意
? 給你一個無向圖,每條邊的兩個方向的邊權可能不同。要求找出一條歐拉回路使得路徑上的邊權的最大值最小。無解輸出"NIE"。
\(2\leq n\leq 1000,1\leq m\leq 2000\)
題解
? 我們先二分答案\(ans\),把邊權大於\(ans\)的邊刪掉。
? 現在圖中還剩下一些有向邊和一些無向邊,也就是說這是一個混合圖。
? 混合圖的歐拉回路怎麽求?
? 先把無向邊定向(方向任意),求出每個點的出度\(d1_i\)和入度\(d2_i\)。如果存在點\(i\)使得\(|d1_i-d2_i|\)為奇數,則無解。因為你怎麽反向都不可能把\(d1_i-d2_i\)變成\(0\)
? 然後把無向邊按定向的反方向在圖中連邊,容量為\(1\)。對於一個點\(i\),如果\(d1_i>d2_i\),則連邊\(i\text{->}T\),容量為\(\frac{d1_i-d2_i}{2}\),否則連邊\(S\text{->}i\),容量為\(\frac{d2_i-d1_i}{2}\)。
? 最後跑一次最大流。如果滿流就有解,否則無解。
還要用並查集判一下是不是連通圖。
? 為什麽這是對的?每流過一條邊就表示把這條邊反向。對這個網絡求最大流就是調整盡可能多的邊。流量平衡就表示一個點的入度和出度相同。
? 這個圖把邊定向得到
?
? 建圖後跑最大流可以得到
? 把滿流邊反向後得到
? 這就是一個歐拉回路了
代碼
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
struct list
{
int v[100010 ];
int w[100010];
int t[100010];
int h[1010];
int n;
void clear()
{
memset(h,0,sizeof h);
n=0;
}
void add(int x,int y,int z)
{
n++;
v[n]=y;
w[n]=z;
t[n]=h[x];
h[x]=n;
}
};
list l;
void add(int x,int y,int z)
{
l.add(x,y,z);
l.add(y,x,0);
}
int d[1010];
int S,T;
int bfs()
{
memset(d,-1,sizeof d);
queue<int> q;
q.push(S);
d[S]=0;
int x,i;
while(!q.empty())
{
x=q.front();
q.pop();
for(i=l.h[x];i;i=l.t[i])
if(l.w[i]&&d[l.v[i]]==-1)
{
d[l.v[i]]=d[x]+1;
if(l.v[i]==T)
return 1;
q.push(l.v[i]);
}
}
return 0;
}
int op(int x)
{
return ((x-1)^1)+1;
}
int dfs(int x,int flow)
{
if(x==T)
return flow;
int c,s=0,i;
for(i=l.h[x];i;i=l.t[i])
if(l.w[i]&&d[l.v[i]]==d[x]+1)
{
c=dfs(l.v[i],min(flow,l.w[i]));
s+=c;
flow-=c;
l.w[i]-=c;
l.w[op(i)]+=c;
if(!flow)
break;
}
return s;
}
int f[1010];
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
int lx[2010],ly[2010],w1[2010],w2[2010];
int d1[2010],d2[2010];
int c[2010];//方向
int n,m;
int abs(int x)
{
return x>0?x:-x;
}
int check(int p)
{
memset(d1,0,sizeof d1);
memset(d2,0,sizeof d2);
int i;
for(i=1;i<=n;i++)
f[i]=i;
for(i=1;i<=m;i++)
{
if(p<w1[i]&&p<w2[i])
return 0;
if(p>=w1[i])
{
c[i]=0;
d1[lx[i]]++;
d2[ly[i]]++;
f[find(lx[i])]=find(ly[i]);
}
else
{
c[i]=1;
d1[ly[i]]++;
d2[lx[i]]++;
f[find(lx[i])]=find(ly[i]);
}
}
for(i=1;i<=n;i++)
{
if(abs(d1[i]-d2[i])&1)
return 0;
if(i>1&&find(i)!=find(i-1))
return 0;
}
l.clear();
S=n+1;
T=n+2;
for(i=1;i<=m;i++)
if(p>=w1[i]&&p>=w2[i])
add(ly[i],lx[i],1);
// else
// add(lx[i],ly[i],1);
int s=0,ans=0;
for(i=1;i<=n;i++)
if(d1[i]>d2[i])
{
add(i,T,(d1[i]-d2[i])/2);
s+=(d1[i]-d2[i])/2;
}
else if(d1[i]<d2[i])
add(S,i,(d2[i]-d1[i])/2);
while(bfs())
ans+=dfs(S,0x7fffffff);
return ans==s;
}
int main()
{
// freopen("bzoj2095.in","r",stdin);
scanf("%d%d",&n,&m);
int i;
for(i=1;i<=m;i++)
scanf("%d%d%d%d",&lx[i],&ly[i],&w1[i],&w2[i]);
int l=1,r=1001;
int mid;
while(l<r)
{
mid=(l+r)>>1;
if(check(mid))
r=mid;
else
l=mid+1;
}
if(l>1000)
printf("NIE\n");
else
printf("%d\n",l);
return 0;
}
【BZOJ2095】【POI2010】Bridge 網絡流