上学路线 解题报告

题目描述
其中 \(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;
}



posted @ 2025-07-07 16:47  XiaoZi_qwq  阅读(7)  评论(0)    收藏  举报