题解:SP287 NETADMIN - Smart Network Administrator
网络流水题。
题意
多测,每次给定
解析
不难想到网络流,但是这个最大经过次数最小很难直接算。于是想到二分。二分出每条边的容量
使用 Dinic 求最大流,时间复杂度:
程序
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define infll 0x3f3f3f3f3f3f3f3f
#define N 10010
#define M 500010
int n,m,k,s,t,tot=1;
int A[N],X[M],Y[M];
ll maxflow;
int Head[N],Son[M],Next[M];
ll Cap[M];
deque<int>Q;
int Cur[N];
ll Dis[N];
inline void add(int x,int y,ll z)
{
Son[++tot]=y;
Cap[tot]=z;
Next[tot]=Head[x];
Head[x]=tot;
}
bool bfs()
{
memset(Dis,0x3f,sizeof(Dis));
memcpy(Cur,Head,sizeof(Cur));
Q.clear();
Q.push_back(s);
Dis[s]=0;
while(!Q.empty())
{
int x=Q.front();
Q.pop_front();
for(int i=Head[x];i;i=Next[i])
{
int y=Son[i];
if(Cap[i]>0&&Dis[y]==infll)
{
Q.push_back(y);
Dis[y]=Dis[x]+1;
if(y==t)return 1;
}
}
}
return 0;
}
ll dfs(int x,ll flow)
{
if(x==t)return flow;
ll res=0;
for(int i=Cur[x];i&&flow;i=Next[i])
{
int y=Son[i];
Cur[x]=i;
if(Cap[i]>0&&Dis[y]==Dis[x]+1)
{
ll k=dfs(y,min(flow,Cap[i]));
if(!k)Dis[y]=infll;
Cap[i]-=k;
Cap[i^1]+=k;
res+=k;
flow-=k;
}
}
return res;
}
void Dinic()//网络流板子
{
while(bfs())maxflow+=dfs(s,infll);
}
bool check(int mid)//每次重新建图跑一遍最大流
{
tot=1;
memset(Head,0,sizeof(Head));
maxflow=0;
for(int i=1;i<=k;i++)
{
add(s,A[i],1);
add(A[i],s,0);
}
for(int i=1;i<=m;i++)
{
add(X[i],Y[i],mid);
add(Y[i],X[i],0);
add(Y[i],X[i],mid);
add(X[i],Y[i],0);
}
Dinic();
return maxflow==k;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int _;
cin>>_;
while(_--)
{
int ans=-1;
cin>>n>>m>>k;
s=n+1;
t=1;
for(int i=1;i<=k;i++)
cin>>A[i];
for(int i=1;i<=m;i++)
cin>>X[i]>>Y[i];
int l=1,r=k;
while(l<=r)//二分答案
{
int mid=(l+r)>>1;
if(check(mid))
{
ans=mid;
r=mid-1;
}
else l=mid+1;
}
cout<<ans<<'\n';
}
return 0;
}