URL
简要题意
给一张n个点m条边的有向图,有边权。
对于一条边允许花费一定代价翻转起点终点。
求至多翻转一条边后[翻转的代价]+[1走到n的代价]+[n走到1的代价]的最小值。
解法
https://codeforces.com/blog/entry/73648?#comment-579708
这个讲得很清楚。
实现
#include <bits/stdc++.h>
using namespace std;
#define rng(i,a,b) for(int i=int(a);i<int(b);i++)
#define rep(i,b) rng(i,0,b)
#define gnr(i,a,b) for(int i=int(b)-1;i>=int(a);i--)
#define per(i,b) gnr(i,0,b)
#define pb push_back
#define eb emplace_back
#define bg begin()
#define ed end()
#define all(x) (x).bg,(x).ed
#define si(x) int((x).size())
#define mp make_pair
#define a first
#define b second
#ifdef LOCAL
#define dmp(x) cerr<<__LINE__<<" "<<#x<<" "<<x<<endl
#else
#define dmp(x) void(0)
#endif
template<class t,class u> void chmax(t&a,u b){if(a<b)a=b;}
template<class t,class u> void chmin(t&a,u b){if(b<a)a=b;}
template<class t> using vc=vector<t>;
template<class t> using vvc=vc<vc<t>>;
using ll=long long;
using uint=unsigned int;
using pi=pair<int,int>;
using vi=vc<int>;
int topbit(signed t){
return t==0?-1:31-__builtin_clz(t);
}
int topbit(ll t){
return t==0?-1:63-__builtin_clzll(t);
}
const int nmax=210;
const int mmax=50010;
struct E{
int u,v,c,d;
int other(int a){
return a^u^v;
}
friend istream& operator>>(istream&i,E&e){
i>>e.u>>e.v>>e.c>>e.d;
e.u--,e.v--;
return i;
}
};
int n,m;
E es[mmax];
vi g[nmax];
int dist[nmax];
int pre[nmax];
bool mark[mmax];
vi path;
void build(){
rep(i,n)g[i]={};
rep(i,m)
g[es[i].u].pb(i);
}
int comb(int a,int b){
return (a==-1||b==-1?-1:a+b);
}
int comb(int a,int b,int c){
return comb(a,comb(b,c));
}
void upd(int&a,int b){
if(b!=-1&&(a==-1||a>b))a=b;
}
void sssp(){
rep(i,n)dist[i]=-1;
dist[0]=0;
priority_queue<pi,vc<pi>,greater<pi>> pq;
pq.emplace(0,0);
while(!pq.empty()){
int v=pq.top().second;
int d=pq.top().first;
pq.pop();
if(d!=dist[v])continue;
for(auto i:g[v]){
int u=es[i].other(v);
int nd=es[i].c+d;
if(dist[u]==-1||nd<dist[u]){
pre[u]=i;
dist[u]=nd;
pq.emplace(nd,u);
}
}
}
rep(i,m)mark[i]=false;
path={};
if(dist[n-1]==-1)return;
int v=n-1;
int tmp=0;
while(v!=0){
int i=pre[v];
tmp+=es[i].c;
path.pb(i);
mark[i]=true;
v=es[i].other(v);
}
reverse(all(path));
}
int d0[nmax][nmax],d1[nmax][nmax];
void slv(int*res,int&best){
build();
sssp();
best=dist[n-1];
rep(i,n)rep(j,n){
int w=(i==j?0:-1);
d0[i][j]=d1[i][j]=w;
}
rep(i,m){
E&e=es[i];
upd(d0[e.u][e.v],e.c);
if(!mark[i])
upd(d1[e.u][e.v],e.c);
}
rep(k,n)rep(i,n)rep(j,n){
upd(d0[i][j],comb(d0[i][k],d0[k][j]));
upd(d1[i][j],comb(d1[i][k],d1[k][j]));
}
//not on path
rep(i,m)if(!mark[i]){
E&e=es[i];
res[i]=best;
upd(res[i],comb(d0[0][e.v],e.c,d0[e.u][n-1]));
}
if(dist[n-1]==-1)return;
rep(i,m)if(mark[i])res[i]=-1;
//on path
rep(i,m)if(mark[i])res[i]=-1;
rep(i,si(path))rng(j,i,si(path)){
int a=es[path[i]].u;
int b=es[path[j]].v;
int w=comb(d0[0][a],d1[a][b],d0[b][n-1]);
rng(k,i,j+1)
upd(res[path[k]],w);
}
}
int res[2][mmax];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n>>m;
rep(i,m)cin>>es[i];
int ans=-1;
int w0,w1;
slv(res[0],w0);
rep(i,m){
E&e=es[i];
if(e.u==0)e.u=n-1;
else if(e.u==n-1)e.u=0;
if(e.v==0)e.v=n-1;
else if(e.v==n-1)e.v=0;
}
slv(res[1],w1);
rep(i,m){
upd(ans,comb(res[0][i],res[1][i],es[i].d));
}
upd(ans,comb(w0,w1));
cout<<ans<<'\n';
}