正题

题目链接:https://www.luogu.com.cn/problem/P6880


题目大意

给出\(n\)个点\(m\)条边的有向图,边有边权和一个翻转权值。

翻转至多一条边使得\(1->n->1\)往返的权值加上翻转权值最小。

\(1\leq n\leq 200,1\leq m\leq 5\times 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\n",ans);
return 0;
}

最新文章

  1. SQl 2005 For XMl 简单查询(Raw,Auto,Path模式)(1)
  2. python核心编程学习记录之基础知识
  3. [转]Android WebView播放视频(包括全屏播放),androidwebview
  4. Android Handler的使用
  5. 关于MSSQL导入导出时主键与约束丢失的问题解决
  6. ConcurrentHashMap和Hashtable区别
  7. aJax提交——服务端不能用request存储数据,session存数据客户端可以接收到
  8. iOS音频篇:AVPlayer的缓存实现
  9. java_spring_依赖注入
  10. C语言调用lua
  11. linux for 使用
  12. springboot学习笔记-4 整合Druid数据源和使用@Cache简化redis配置
  13. Spring Boot 2.x (八):日志框架的使用
  14. 【转】Android中保持Service的存活
  15. JavaScript之函数(上)
  16. 【js】使用javascript 实现静态网页分页效果
  17. Appium环境的安装以及一路上的坑
  18. ztree带有选项框的树形菜单使用
  19. HTTP请求/响应报文结构
  20. golang-build-error

热门文章

  1. 你知道那些JVM性能调优
  2. Spring-Boot的动态代理AOP原理
  3. taro小程序地址选择组件
  4. .net core2.1 迁移.net core 3.1
  5. RestTemplate post请求 Controller 接收不到值的解决方案 postForObject方法源码解析
  6. 学习Java的9张思维导图
  7. Maven解决依赖冲突
  8. 每天迁移MySQL历史数据到历史库Python脚本
  9. 重启网络服务 network 出现问题
  10. 如何实现LRU缓存