SP287
前言
我们可以发现这道题一眼就是二分了,但是唯一的问题就是如何写 check 函数。
思路
这里我们可以看到 标签 中有 网络流 那么我们就来想一下如何写,这里我们可以将 S 与所有的特殊点都连上一条流量为 \(1\) 的边,然后由于我们传进来的一个数为 \(x\) 然后在将所有正常的边都变成流量为 \(x\) 的边,这里即可代表每一条边的最多能走 \(x\) 次。
然后我们直接跑一个正常的网络流即可,然后我们就判断 \(maxflow\) 与 \(k\) 的关系即可,若大于等于就满足条件。
代码
#include <bits/stdc++.h>
using namespace std ;
#define int long long
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define rep1(i,x,y) for(int i=x;i>=y;i--)
#define fire signed
#define kong putchar(' ')
#define end putchar('\n')
#define in(x) scanf("%lld",&x)
#define lcm(x,y) x*y/__gcd(x,y)
#define il inline
il void print(int x) {
if(x>=10) print(x/10);
putchar(x%10+'0');
}
int tot=1;
const int N=1e5+10;
int head[N],n,m,k;
struct node {
int x,y,z;
} edg[N];
int d[N],s;
int a[N],t;
void add(int x,int y,int z) {
edg[++tot]= {y,head[x],z};
head[x]=tot;
if(x!=s) edg[++tot]= {x,head[y],z};
else edg[++tot]={x,head[y],0};
head[y]=tot;
}
int x[N],y[N];
int bfs() {
queue<int>q;
q.push(s);
memset(d,0,sizeof d);
d[s]=1;
while(q.size()) {
int x=q.front();
q.pop();
for(int i=head[x]; ~i; i=edg[i].y) {
int to=edg[i].x;
if(!d[to]&&edg[i].z) {
d[to]=d[x]+1;
q.push(to);
if(to==t) return 1;
}
}
}
return false;
}
int dinic(int x,int flow) {
if(x==t) return flow;
int pl=false;
for(int i=head[x]; ~i&&flow; i=edg[i].y) {
int to=edg[i].x;
if(d[to]==d[x]+1&&edg[i].z) {
int k=dinic(to,min(edg[i].z,flow));
if(!k) d[to]=-1;
edg[i].z-=k;
pl+=k;
edg[i^1].z+=k;
flow-=k;
}
}
return pl;
}
bool check(int ff) {
memset(head,-1,sizeof head);
tot=1;
t=1;
s=n+1;
rep(i,1,k) add(s,a[i],1);
rep(i,1,m) add(x[i],y[i],ff);
int flow=0;
while(bfs()) flow+=dinic(s,INT_MAX);
return flow>=k;
}
fire main() {
int T;
cin>>T;
while(T--) {
in(n),in(m),in(k);
rep(i,1,k) in(a[i]);
rep(i,1,m) cin>>x[i]>>y[i];
int l=0,r=k+1,ans=0;
while(l<=r) {
int mid=l+r>>1;
if(check(mid)) r=mid-1,ans=mid;
else l=mid+1;
}
print(ans);
end;
}
return false;
}

浙公网安备 33010602011771号