题目描述
有一张无向图,开始的时候所有边权为1,所有点没有权值,现在给定一个整数k,表示可以将k个点的点权设置为1,求点0到n-1的最短路最长是多少
Solution
网络流好题[然而本蒟蒻还是不会][这个建图是真的神仙…]
最短路最长,最大化最小的问题,考虑二分,我们先二分出一个mid,表示假设最短路最长是mid
然后建图建mid+1层,将每个点拆成两个点si和ti,从si向ti连一条流量为1的边,表示割掉这条边需要1的代价[割掉了就是+1s]
为了保证每个点只被选择一次,从这层的si向下一层的ti连一条流量为正无穷的边。然后对于本来图中存在的边<x,y>,从这层的tx向下一层的sy连一条流量为无穷的边
从这层的sn-1向下一层的sn-1连流量为无穷的边
如果从第一层的t0到mid+1层的sn-1的最小割<=k 向[mid+1,r]找,否则向[l,mid-1]找
[本蒟蒻理解这个建图理解了一个晚上x]
[效果大概长这样?][我画的图还是好丑啊]
然后建完图跑网络流就可以啦!
总效率O(能过)
Code
-
#include <bits/stdc++.h>
-
using namespace std;
-
int T,K,N,M;
-
const int fish1=101*101*4;
-
const int fish2=8*101*101*101;
-
vector<int> vec[fish1];
-
int cnt,nex[fish2],las[fish2],Arrive[fish2],Flow[fish2];
-
int d[fish1];
-
void jt(int u,int v,int FF)
-
{
-
cnt++;
-
nex[cnt]=las[u];
-
las[u]=cnt;
-
Arrive[cnt]=v;
-
Flow[cnt]=FF;
-
cnt++;
-
nex[cnt]=las[v];
-
las[v]=cnt;
-
Arrive[cnt]=u;
-
Flow[cnt]=0;
-
}
-
bool BFS()
-
{
-
memset(d,0,sizeof(d));
-
d[2]=1;
-
queue<int> qwq;
-
qwq.push(2);
-
while (!qwq.empty())
-
{
-
int R=qwq.front();
-
qwq.pop();
-
for (int i=las[R];i;i=nex[i])
-
{
-
if (Flow[i])
-
{
-
int RR=Arrive[i];
-
if (!d[RR])
-
{
-
d[RR]=d[R]+1;
-
qwq.push(RR);
-
}
-
}
-
}
-
}
-
return d[T]>0;
-
}
-
int DFS(int Now,int flow)
-
{
-
if (!flow) return flow;
-
if (Now==T) return flow;
-
int ans=0;
-
bool b=0;
-
for (int i=las[Now];i;i=nex[i])
-
{
-
if (Flow[i])
-
{
-
int v=Arrive[i];
-
if (d[v]!=d[Now]+1) continue;
-
int tmp=DFS(v,min(Flow[i],flow));
-
if (tmp)
-
{
-
flow-=tmp;
-
ans+=tmp;
-
Flow[i]-=tmp;
-
Flow[i^1]+=tmp;
-
b=1;
-
if (!flow) break;
-
}
-
}
-
}
-
if(!b) d[Now]=-1;
-
return ans;
-
}
-
int Dinic()
-
{
-
int ans=0;
-
while (BFS())
-
{
-
ans+=DFS(2,1e6);
-
if (ans>K) return ans;
-
}
-
return ans;
-
}
-
bool Check(int Now)
-
{
-
cnt=1;
-
memset(las,0,sizeof(las));
-
for (int i=1;i<=Now;i++)
-
{
-
for (int j=N-1;j>1;j--)
-
jt((i-1)*2*N+j*2-1,(i-1)*2*N+j*2,1),jt((i-1)*2*N+j*2-1,i*2*N+j*2,1e6);
-
for (int j=1;j<=N;j++)
-
for (int k=vec[j].size()-1;k>=0;k--)
-
jt((i-1)*2*N+j*2,i*2*N+(vec[j][k]*2)-1,1e6);
-
jt((i-1)*2*N+N*2-1,i*2*N+(N*2)-1,1e6);
-
}
-
T=(Now+1)*2*N-1;
-
return Dinic()<=K;
-
}
-
int main()
-
{
-
freopen("min.in","r",stdin);
-
freopen("min.out","w",stdout);
-
scanf("%d%d%d",&N,&M,&K);
-
for (int i=1;i<=M;i++)
-
{
-
int u,v;
-
scanf("%d%d",&u,&v);
-
u++;
-
v++;
-
vec[u].push_back(v);
-
vec[v].push_back(u);
-
}
-
int l=1,r=2*N,anss;
-
while (l<=r)
-
{
-
int mid=(l+r)/2;
-
if (Check(mid)) anss=mid,l=mid+1;
-
else r=mid-1;
-
}
-
printf("%d",anss+1);
-
return 0;
-
}