题意:给一个有重边的图,删某条边有一个代价wi,求最小的代价和,使得此图的最短路长度边长。
思路:
先处理出最短路相关的图,即保留:d[i.to]=d[now]+d[i.cost]的边。
然后在此图上求最小割(最大流。
因为处理出来的是无环图,所以dinic可以跑的飞快
https://www.lydsy.com/JudgeOnline/problem.php?id=1266
这里用bzoj。
无向图,建图双向判断。
/**************************************************************
Problem: 1266
User: rshs
Language: C++
Result: Accepted
Time:868 ms
Memory:24088 kb
****************************************************************/
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define LL long long
#define FI first
#define SE second
#define MP make_pair
#define PII pair<int,int>
const int mod = 1e9+7;
const int MX = 2e5+5;
LL d[MX];int vis[MX];
struct No{LL co,to;};
bool operator<(const No &x,const No &y){return x.co>y.co;}
vector<No>og[MX];
struct no{LL to,cap,rev;}; //arc
vector<no>g[MX]; //图
LL level[MX]; //到起点的距离
LL iter[MX]; //当前弧,在其之前的边已经没用了
void addarc(int s,int e,int c){
g[s].push_back((no){e,c,g[e].size()});
g[e].push_back((no){s,0,g[s].size()-1});
}
LL aa[MX],bb[MX],cc[MX],dd[MX];
//更新层次,即level
void bfs(int s){
memset(level,-1,sizeof(level));
level[s]=0;
queue<int>q;
q.push(s);
while(!q.empty()){
int now=q.front();q.pop();
for(int i=0;i<(int)g[now].size();i++){
no &arc=g[now][i];
if(level[arc.to]!=-1||arc.cap<=0) continue;
level[arc.to]=level[now]+1;
q.push(arc.to);
}
}
}
//寻找增广路
LL dfs(int v,int t,LL f){
if(v==t) return f;
for(iter[v];iter[v]<(int)g[v].size();iter[v]++){
no &arc=g[v][iter[v]];
if(arc.cap<=0||level[arc.to]!=level[v]+1) continue;
LL d=dfs(arc.to,t,min(f,arc.cap));
if(d>0) {
arc.cap=arc.cap-d;
g[arc.to][arc.rev].cap+=d;
return d;
}
}
return 0;
}
LL Dinic(int s,int t){
LL re=0;
while(1){
bfs(s);
memset(iter,0,sizeof(iter));
if(level[t]==-1) return re;
LL f;
while((f=dfs(s,t,LLONG_MAX))>0)
re=re+f;
}
return re;
}
map<PII,int>ma;
signed main(){
int n,m;cin>>n>>m;ma.clear();
for(int i=1;i<=n;i++)d[i]=LLONG_MAX/2,vis[i]=0,og[i].clear(),g[i].clear();
for(int i=1;i<=m;i++){
cin>>aa[i]>>bb[i]>>cc[i]>>dd[i];
og[aa[i]].push_back(No{cc[i],bb[i]});
og[bb[i]].push_back(No{cc[i],aa[i]});
}
priority_queue<No>q;d[1]=0;q.push(No{0,1});
while(!q.empty()){
int now=q.top().to;q.pop();
if(vis[now])continue;
vis[now]=1;
for(int i=0;i<(int)og[now].size();i++){
if(og[now][i].co+d[now]<d[og[now][i].to]){
d[og[now][i].to]=og[now][i].co+d[now];
q.push(No{d[og[now][i].to],og[now][i].to});
}
}
}
for(int i=1;i<=m;i++){
if(d[aa[i]]+cc[i]==d[bb[i]])addarc(aa[i],bb[i],dd[i]);
if(d[bb[i]]+cc[i]==d[aa[i]])addarc(bb[i],aa[i],dd[i]);
}
cout<<d[n]<<endl;
cout<<Dinic(1,n)<<endl;
return 0;
}