上学路线 解题报告
其中 \(N \leq 500 M \leq 12470\)
第一个问很简单,直接跑SPFA或DJ都可以。
关键是第二个问,我们可以转化一下题意:去掉某些边,让最短路权值变大,等价于去掉某些边,使得只通过原最短路上的边无法到达终点。
“删去某些边,使得原图不连通,并且花费最小。”这不就是最小割吗!所以在仅由最短路上的边构成的图上跑最小割就能解决第二问。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define add(u,v,w,c) adds(u,v,w,c),adds(v,u,w,c)
using namespace std;
typedef long long ll;
inline int read(){
register int x=0;
char c=getchar();
while(c<'0' || '9'<c) c=getchar();
while('0'<=c && c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
return x;
}
const int N=510,M=125000;
int n,m;
struct Edge{int from,f,to,dis,flow;}e[M<<1];
int num=1,h[N];
void adds(int f,int t,int d,int flow){
e[++num].from=h[f],e[num].to=t,h[f]=num;
e[num].f=f,e[num].dis=d,e[num].flow=flow;
}
int dis[N];
bool vis[N];
void DJ(){
memset(dis,inf,sizeof(dis));
dis[1]=0;
while(true){
int u=0,mn=inf;
for(int i=1;i<=n;i++)
if(!vis[i] && dis[i]<mn)
mn=dis[i],u=i;
if(!u) break;
vis[u]=true;
for(int i=h[u],v;i;i=e[i].from){
v=e[i].to;
if(!vis[v] && dis[v]>dis[u]+e[i].dis)
dis[v]=dis[u]+e[i].dis;
}
}
}
int maxflow,d[N],cur[N];
queue<int> q;
bool bfs(){
memset(vis,0,sizeof(vis));
q.push(1);vis[1]=true;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=h[u],v;i;i=e[i].from){
v=e[i].to;
if(!vis[v] && e[i].flow>0){
d[v]=d[u]+1;
vis[v]=true;
q.push(v);
}
}
}
return vis[n];
}
int dfs(int u,int flow){
if(u==n || flow==0) return flow;
int ans=0,get;
for(int &i=cur[u],v;i;i=e[i].from){
v=e[i].to;
if(d[u]+1==d[v] && (get=dfs(v,min(flow,e[i].flow)))>0){
e[i].flow-=get,e[i^1].flow+=get;
ans+=get,flow-=get;
if(!flow) return ans;
}
}
return ans;
}
void dinic(){
while(bfs()){
memcpy(cur,h,sizeof(cur));
int x=dfs(1,inf);
while(x) maxflow+=x,x=dfs(1,inf);
}
}
int main(){
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
n=read(),m=read();
for(int i=1,u,v,w,c;i<=m;i++) u=read(),v=read(),w=read(),c=read(),add(u,v,w,c);
DJ();
for(int i=2;i<=num;i+=2){
if(dis[e[i].f]+e[i].dis!=dis[e[i].to])
e[i].flow=0;
if(dis[e[i^1].f]+e[i^1].dis!=dis[e[i^1].to])//只要你没有流量,有你没你都一样
e[i^1].flow=0;
}
dinic();
printf("%d\n%d",dis[n],maxflow);
return 0;
}