不难看出这是一道差分约束的题目。

但是如果想按照通常的题目那样去建边的话,就会发现这句话——相邻两站的距离至少是1公里——建边后就直接让整个题出现了负环(默认是按求最短路建边),没法做了。

这时我们就需要使用断环为链的技巧。

可以设\(len\)为地铁环线总长

那么就需要把\(a→b(a>b)\)的限制条件转换为\(b→a\)的限制条件,比如\(dis(a,b)\leq k\)转换为\(dis(b,a)\geq len-k\)。总算能连边建图惹

如果现在要判断是否有解,那方法肯定是\(spfa\)判负环。

但问题在于\(len\)是未知量,如果用\(len\)表示每一条边,那么\(e_i=len\pm d_i\ or\ \pm\ d_i\)。

因为有没有解的关键在于有没有负环,所以:

考虑图上每一个环, 其权值一定可以表示为 \(val=k×len+b\) 的形式. 那么现在分类讨论一下每一个环.

  • \(k=0\) 且 \(b<0\) 时, \(val<0\),为负环,一定无解;
  • \(k<0\) 且 \(b<0\) 时, \(val<0\),为负环,一定无解;
  • \(k<0\) 且 \(b>0\) 时, 如果出现\(val<0\),可以通过减小 \(len\) 来消除负环;
  • \(k>0\) 时, 如果出现\(val<0\),可以通过增大 \(len\) 来消除负环。

这样思考会发现\(len\)的合法大小一定是一段连续区间

所以可以确定一个\(INF\),然后二分\(len\),由上述规律找到\(len\)的合法区间的左右端点,如果右端点接近\(INF\)则判断为无数个解。

\(tips\):

  • 凡是没有说明联通的图都要小心;
  • 可能只有一个点;
  • 因为\(e_i=len\pm d_i\ or\ \pm\ d_i\),而\(len\)是变量,所以建边的时候存\(len\)的系数和\(d_i\);
  • 若一个点入队次数超过n,则有负权环,然后要判断\(k\)的值,来决定二分方向,要记录来时的边 废话,并且把环取出来 可能有小尾巴呀;

代码:

#include <set>
#include <map>
#include <queue>
#include <vector>
#include <math.h>
#include <string>
#include <utility>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <iostream>
#include <algorithm>
using namespace std; struct edge{
int nx,from,to,k,v;
}; #define N 55
#define M 55
#define INF 100000000000
#define mid ((l+r)>>1) int T,n,m1,m2;
int cnt,head[N];
int st,pre[N],ar[N],inq[N],vis[N];
long long L,R,dis[N];
queue <int> Q;
edge e[M*2+N*2]; inline void clear(){
cnt=L=R=0;
memset(head,0,sizeof(head));
} inline void add(int u,int v,int k,int w){
e[++cnt]=edge{head[u],u,v,k,w};
head[u]=cnt;
} inline int spfa(long long len){
while(!Q.empty()) Q.pop();
memset(ar,0,sizeof(ar));
memset(inq,0,sizeof(inq));
memset(pre,0,sizeof(pre));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;++i) dis[i]=INF;
Q.push(st); inq[st]=1; dis[st]=0;
while(!Q.empty()){
int x=Q.front(); Q.pop(); inq[x]=0;
for(int i=head[x];i;i=e[i].nx){
int y=e[i].to;
if(dis[y]>dis[x]+e[i].k*len+e[i].v){
dis[y]=dis[x]+e[i].k*len+e[i].v;
pre[y]=i; ar[y]=ar[x]+1;
if(ar[y]>n+1){
int tail,k=0;
for(int j=y;j;j=e[pre[j]].from)
if(vis[j]){tail=j;break;}
else vis[j]=1;
k+=e[pre[tail]].k;
for(int j=e[pre[tail]].from;j!=tail;j=e[pre[j]].from)
k+=e[pre[j]].k;
if(k==0) return 1;
if(k>0) return 2;
if(k<0) return 3;
}
if(!inq[y]) inq[y]=1,Q.push(y);
}
}
}
return 4;
} int main(){
scanf("%d",&T);
while(T--){
clear();
scanf("%d%d%d",&n,&m1,&m2);
add(1,n,1,-1);
for(int i=2;i<=n;++i) add(i,i-1,0,-1);
for(int i=1;i<=n;++i) add(st,i,0,0);
int a,b,d;
for(int i=1;i<=m1;++i){
scanf("%d%d%d",&a,&b,&d); ++a,++b;
if(a<b) add(b,a,0,-d);
else add(b,a,1,-d);
}
for(int i=1;i<=m2;++i){
scanf("%d%d%d",&a,&b,&d); ++a,++b;
if(a<b) add(a,b,0,d);
else add(a,b,-1,d);
}
int flag;
bool OK=0;
long long l=1,r=INF;
while(l<=r){
flag=spfa(mid);
if(flag==1) break;
else if(flag==2) l=mid+1;
else if(flag==3) r=mid-1;
else OK=1,L=mid,r=mid-1;
}
l=1,r=INF;
while(l<=r){
flag=spfa(mid);
if(flag==1) break;
else if(flag==2) l=mid+1;
else if(flag==3) r=mid-1;
else OK=1,R=mid,l=mid+1;
}
if(!OK) printf("0\n");
else if(R>=INF) printf("-1\n");
else printf("%lld\n",R-L+1);
}
return 0;
}

参考了Rothen的博客

我也不知道他 blog 为啥没了,也不敢问

[题解] 51 nod 1340 地铁环线的更多相关文章

  1. 【51nod】1340 地铁环线

    今天头非常疼,躲在家里没去机房 反正都要颓废了,然后花了一上午研究了一下这道神题怎么做-- 题解 首先我们发现,如果我们设\(dis[i]\)为从\(0\)节点走到\(i\)节点的距离 那么题目中给出 ...

  2. 题解 [51nod1340]地铁环线

    题解 [51nod1340]地铁环线 题面 解析 本文参考这篇博客 一开始看到只有120行就打算写一写, 结果一刚就是三个星期摆摆摆 本来是当查分约束入门学的. step 1 首先来考虑下如果已知总长 ...

  3. 【51nod 1340】地铁环线

    题目 有一个地铁环线,环线中有N个站台,标号为0,1,2,...,N-1.这个环线是单行线,一共由N条有向边构成,即从0到1,1到2,..k到k+1,...,N-2到N-1,N-1到0各有一条边.定义 ...

  4. 51 nod 1766 树上的最远点对(线段树+lca)

    1766 树上的最远点对 基准时间限制:3 秒 空间限制:524288 KB 分值: 80 难度:5级算法题   n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个 ...

  5. 51 nod 1439 互质对(Moblus容斥)

    1439 互质对 题目来源: CodeForces 基准时间限制:2 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 有n个数字,a[1],a[2],…,a[n].有一个集合,刚开 ...

  6. 51 nod 1495 中国好区间

    1495 中国好区间 基准时间限制:0.7 秒 空间限制:131072 KB 分值: 80 难度:5级算法题   阿尔法在玩一个游戏,阿尔法给出了一个长度为n的序列,他认为,一段好的区间,它的长度是& ...

  7. 51 nod 1427 文明 (并查集 + 树的直径)

    1427 文明 题目来源: CodeForces 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 160 难度:6级算法题   安德鲁在玩一个叫“文明”的游戏.大妈正在帮助他. 这个游 ...

  8. 51 nod 1055 最长等差数列(dp)

    1055 最长等差数列 基准时间限制:2 秒 空间限制:262144 KB 分值: 80 难度:5级算法题 N个不同的正整数,找出由这些数组成的最长的等差数列.     例如:1 3 5 6 8 9 ...

  9. 51 nod 1421 最大MOD值

    1421 最大MOD值 题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 有一个a数组,里面有n个整数.现在要从中找到两个数字(可以 ...

随机推荐

  1. springboot-数据库访问之jpa

    什么是springDate? springData的作用: 整体简化的架构: JPA :Java Persistence API 如果没有springData 我们需要去学每一种对应的jpa实现, 有 ...

  2. MySQL安装速成指南(ZIP)

    MySQL初始化数据库 第一步:将MySQL ZIP压缩包进行解压 第二部:在MySQL主目录创建my.ini文件,并添加以下内容 [client] port=3306 socket=/tmp/mys ...

  3. Spring 的 jdbcTemplate 操作

    1.Spring框架是一站式框架 (1)针对 JavaEE 三层,每一层都有解决技术 (2)在 dao 层,使用 jdbcTemplate 2.Spring对不同的持久化层的技术都进行了封装 (1)j ...

  4. 关于CDN那些事

    对于前端性能优化我们不得不了解的几个知识点:CDN.HTTP header信息 今天我就来谈谈我对cdn的理解 1.CDN是什么:CDN全称是Content Delivery Network,即内容分 ...

  5. DOM 小总结

    DOM 是什么 文档对象模型,是针对 HTML 和 XML 文档的一个 API (应用程序编程接口), 描绘了一个层次化的节点树. D: document 当 web 浏览器浏览一个页面的时候,DOM ...

  6. css使div居中

    每次想要使div居中都会设置position:absolute;,发现设置其他控件位置时会出现问题,所以采用以下办法: margin:0 auto;

  7. 给一个非矩形数组(Nonrectangular Arrays)

    Nonrectangular Arrays(非矩形数组)  public class Test {     public static void main(String[] args) {       ...

  8. window nginx 简单搭建服务器访问静态资源

    nginx命令: 启动: start nginx 停止:nginx -s stop ||  nginx -s quit 注:stop是快速停止nginx,可能并不保存相关信息:quit是完整有序的停止 ...

  9. nodejs教程---基于expressJs框架,实现文件上传(upload)?

    文件上传功能在nodejs初期是一件很难实现的功能,之后出现了formidable勉强能解决这个问题,但是express框架出现之后基于这个框架开发的中间件有更好的方法来处理文件上传,这个中间件就是m ...

  10. BootstrapBlazor实战 Tree树形控件使用(2)

    继续上篇实战BootstrapBlazor树型控件Tree内容, 本篇主要讲解整合Freesql orm快速制作数据库后台维护页面 demo演示的是Sqlite驱动,FreeSql支持多种数据库,My ...