正题
题目链接:https://www.luogu.com.cn/problem/P6880
题目大意
给出(n)个点(m)条边的有向图,边有边权和一个翻转权值。
翻转至多一条边使得(1->n->1)往返的权值加上翻转权值最小。
(1leq nleq 200,1leq mleq 5 imes 10^4)
解题思路
考虑到(n)很小可以从这个方向入手。
有时翻转会使得最短路变长,这个时候当且仅当这条边是最短路的必经边,而图上最多有(n-1)条必经边,所以我们如果翻转必经边时直接暴力重新计算一次最短路,否则我们就用预处理的信息来计算。
因为点很少,暴力的(dij)比堆优化快
时间复杂度(O(n(n^2+m)))
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
#define mp(x,y) make_pair(x,y)
using namespace std;
const ll N=210,M=5e4+10;
struct node{
ll to,next,w,v,ban;
}a[M<<1];
ll n,m,tot,ls[N],f[N],g[N],F[N],G[N],ff[N],gg[N],from[N],grom[N],ans;
bool v[N];
void addl(ll x,ll y,ll w,ll v,ll ban){
a[++tot].to=y;
a[tot].next=ls[x];
a[tot].v=v;a[tot].ban=ban;
ls[x]=tot;a[tot].w=w;
return;
}
void dij(ll *f,ll s,ll op=0){
memset(v,0,sizeof(v));f[s]=0;
for(int i=1;i<=n;i++){
int x=0;
for(int j=1;j<=n;j++)
if(!v[j])x=(f[j]<f[x])?j:x;
v[x]=1;
for(ll i=ls[x];i;i=a[i].next){
ll y=a[i].to;
if(a[i].ban)continue;
if(f[x]+a[i].w<f[y]){
f[y]=f[x]+a[i].w;
if(op==1)from[y]=i;
if(op==2)grom[y]=i;
}
}
}
return;
}
void bij(ll *f,ll s,ll op=0){
memset(v,0,sizeof(v));f[s]=0;
for(int i=1;i<=n;i++){
int x=0;
for(int j=1;j<=n;j++)
if(!v[j])x=(f[j]<f[x])?j:x;
v[x]=1;
for(ll i=ls[x];i;i=a[i].next){
ll y=a[i].to;
if(!a[i].ban)continue;
if(f[x]+a[i].w<f[y])
f[y]=f[x]+a[i].w;
}
}
return;
}
signed main()
{
scanf("%lld%lld",&n,&m);tot=1;
for(ll i=1;i<=m;i++){
ll x,y,c,d;
scanf("%lld%lld%lld%lld",&x,&y,&c,&d);
addl(x,y,c,d,0);addl(y,x,c,d,1);
}
memset(f,0x3f,sizeof(f));dij(f,1,1);
memset(g,0x3f,sizeof(g));dij(g,n,2);
memset(F,0x3f,sizeof(F));bij(F,n);
memset(G,0x3f,sizeof(G));bij(G,1);
ans=f[n]+g[1];
for(ll x=1;x<=n;x++){
for(ll i=ls[x];i;i=a[i].next){
if(a[i].ban)continue;
ll y=a[i].to,w1=f[n],w2=g[1];
if(f[x]+a[i].w+F[y]==f[n]&&i==from[y]){
a[i].ban=1;a[i^1].ban=0;
memset(ff,0x3f,sizeof(ff));dij(ff,1);
w1=ff[n];a[i].ban=0;a[i^1].ban=1;
}
else w1=min(w1,f[y]+a[i].w+F[x]);
if(g[x]+a[i].w+G[y]==g[1]&&i==grom[y]){
a[i].ban=1;a[i^1].ban=0;
memset(gg,0x3f,sizeof(gg));dij(gg,n);
w2=gg[1];a[i].ban=0;a[i^1].ban=1;
}
else w2=min(w2,g[y]+a[i].w+G[x]);
ans=min(ans,w1+w2+a[i].v);
}
}
if(ans>=2e18)puts("-1");
else printf("%lld
",ans);
return 0;
}