题目链接
一个无向图,走最短路从起点走到终点,问最少需要删除多少边使得其不能从起点走到终点,问最多删除多少点使得其能走到终点。
思路:
最大流+最短路
先求出所有在最短路上的边,对这些边重建图。将其权值改为1,那么其最大流就是其最小割。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2110;
const int maxm=12e4+10;
const int inf=0x3f3f3f3f;
int head[maxn],vis[maxn],dis[maxn],x[maxm],y[maxm],z[maxm],sum[maxn],len,nedge,n,m,st,en;
struct Edge
{
int v,w;
int next;
}edge[maxm<<1];
void addedge(int u,int v,int w)
{
edge[nedge].v=v;
edge[nedge].w=w;
edge[nedge].next=head[u];
head[u]=nedge++;
}
int spfa()
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
sum[i]=dis[i]=(i==st)?0:inf;
queue<int>q;
q.push(st);
vis[st]=1;
while(q.size())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v ;
if(edge[i].w&&dis[u]+edge[i].w<dis[v])
{
dis[v]=dis[u]+edge[i].w;
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
return dis[en];
}
bool bfs()
{
queue<int>q;
memset(dis,-1,sizeof(dis));
dis[st]=0;
q.push(st);
while(q.size())
{
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v ;
if(edge[i].w>0&&dis[v]<0)
{
dis[v]=dis[u]+1;
q.push(v);
}
}
}
if(dis[en]>0)
return true ;
return false ;
}
int dfs(int x,int mx)
{
if(x==en)
return mx;
int i,ans=0,a;
for(i=head[x];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(dis[v]==dis[x]+1&&edge[i].w>0&&(a=dfs(v,min(mx,edge[i].w))))
{
edge[i].w-=a;
edge[i^1].w+=a;
ans+=a;
mx-=a;
if(!mx)
break;
}
}
if(!ans)
dis[x] = -1;
return ans;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(head,-1,sizeof(head));
nedge=0;
len=0;
for(int i=0;i<m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
x[len]=u,y[len]=v,z[len++]=w;
x[len]=v,y[len]=u,z[len++]=w;
}
st=1,en=n;
int mi=spfa();
if(mi==inf)
{
printf("0 0\n");
continue;
}
memset(head,-1,sizeof(head));
nedge=0;
for(int i=0;i<len;i++)
if(dis[x[i]]+z[i]==dis[y[i]])
{
addedge(x[i],y[i],1);
addedge(y[i],x[i],0);
}
mi=spfa();
int ans=0,res;
while(bfs())
while(res=dfs(st,inf))
ans+=res;
printf("%d %d\n",ans,m-mi);
}
return 0;
}