题意:
给出一个n个点m条边的无向图,每一条边有长度和去掉的代价,先求1号点到n号点的长度最短路,在求去掉最小代价的一些边,使1到n的长度最短路变大
题解:
求最短路直接SPFA就行了,然后在最短路径图上跑一个代价的最小割就行了。
最短路劲图就是图上的每一条边都在某条(些)最短路上,建图的方法是判断一条路径两个端点x,y是否满足dis[x]==dis[y]+当前路径的长度。
在这个图上跑最小割就行,因为不在最短路径图上的边去掉也不会对任意一条最短路有影响,所以那些边就不用管了。
下面是代码
#include <bits/stdc++.h>
using namespace std;
int n,m,dis[500001],head[500001],cnt,hed[500001];
int inq[500001],q[500001],h,t,res,dep[500001];
struct node
{
int from,to,dis,c,next,other;
}ji[500000],a[500001],b[500001];
void add(int from,int to,int dis)
{
a[++cnt].to=to;
a[cnt].dis=dis;
a[cnt].next=head[from];
head[from]=cnt;
}
void ins(int from,int to,int c)
{
int k1,k2;
++cnt;
k1=cnt;
b[cnt].to=to;
b[cnt].c=c;
b[cnt].next=hed[from];
hed[from]=cnt;
++cnt;
k2=cnt;
b[cnt].to=from;
b[cnt].c=0;
b[cnt].next=hed[to];
hed[to]=cnt;
b[k1].other=k2;
b[k2].other=k1;
}
void spfa()
{
memset(dis,127/3,sizeof(dis));
q[1]=1;
dis[1]=0;
h=1;t=2;
while(h!=t)
{
int x=q[h];
inq[x]=0;
for(int i=head[x];i;i=a[i].next)
{
int y=a[i].to;
if(dis[y]>dis[x]+a[i].dis)
{
dis[y]=dis[x]+a[i].dis;
if(!inq[y])
{
q[t++]=y;
inq[y]=1;
}
}
}
h++;
}
}
int bfs()
{
memset(dep,0,sizeof(dep));
q[1]=1;
h=1;t=2;
dep[1]=1;
while(h!=t)
{
int x=q[h];
for(int i=hed[x];i;i=b[i].next)
{
int y=b[i].to;
if(b[i].c&&dep[y]==0)
{
dep[y]=dep[x]+1;
q[t++]=y;
}
}
h++;
}
if(dep[n]>0)
return 1;
else
return 0;
}
int flow(int x,int f)
{
if(x==n)
return f;
int s=0,t;
for(int i=hed[x];i;i=b[i].next)
{
int y=b[i].to;
if(b[i].c&&dep[y]==dep[x]+1&&s<f)
{
s+=(t=flow(y,min(b[i].c,f-s)));
b[i].c-=t;
b[b[i].other].c+=t;
}
}
if(s==0)
dep[x]=0;
return s;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v,x,y;
scanf("%d%d%d%d",&ji[i].from,&ji[i].to,&ji[i].dis,&ji[i].c);
add(ji[i].from,ji[i].to,ji[i].dis);
add(ji[i].to,ji[i].from,ji[i].dis);
}
spfa();
printf("%d\n",dis[n]);
cnt=0;
for(int i=1;i<=m;i++)
{
if(dis[ji[i].from]==dis[ji[i].to]+ji[i].dis)
ins(ji[i].to,ji[i].from,ji[i].c);
if(dis[ji[i].to]==dis[ji[i].from]+ji[i].dis)
ins(ji[i].from,ji[i].to,ji[i].c);
}
while(bfs())
res+=flow(1,2e9);
printf("%d\n",res);
return 0;
}