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

但是如果想按照通常的题目那样去建边的话,就会发现这句话——相邻两站的距离至少是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. 接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)?

    接口可以继承接口,而且支持多重继承.抽象类可以实现(implements)接口,抽象类可继承具体类也可以继承抽象类.

  2. kafka中的回调函数

    kafka客户端中使用了很多的回调方式处理请求.基本思路是将回调函数暂存到ClientRequest中,而ClientRequest会暂存到inFlightRequests中,当返回response的 ...

  3. request表示HttpServletRequest对象?

    request表示HttpServletRequest对象.它包含了有关浏览器请求的信息,并且提供了几个用于获取cookie, header, 和session数据的有用的方法. response表示 ...

  4. java-可变参数hei

    /* 使用前提: 当前方法的参数的数据类型已经确定,但是参数的个数不确定,就可以使用可变参数 使用格式: 定义方法是使用 修饰符 返回类型 方法名(数据类型... 变量名){} 可变参数的原理: 可变 ...

  5. Python - random库介绍

  6. BMZCTF phar???

    pchar??? 补充知识点 开始这题之前我们先补充一个知识点 phar 的文件包含 和上面类似先创建一个phar 标准包,使用 PharData 来创建,然后添加文件进去phar里面. 然后在文件包 ...

  7. PC端操作系统、移动端操作系统、嵌入式操作系统

    左侧部分已是历史的操作系统,右侧的还是活跃的操作系统.安卓系统Android 是Google开发的基于Linux平台的开源手机操作系统.它包括操作系统.用户界面和应用程序-- 移动电话工作所需的全部软 ...

  8. 【转】ng-class的用法

    原文出处:https://segmentfault.com/a/11... 在开发中我们通常会遇到一种需求:一个元素在不同的状态需要展现不同的样子. 而在这所谓的样子当然就是改变其css的属性,而实现 ...

  9. 通读Python官方文档之wsgiref(未完成)

    wsgirf-WSGI功能及参考实现 源码:Lib/wsgiref Web服务器网关接口(Web Server Gateway Interface, WSGI),是用Python写的一个服务器软件和w ...

  10. 体温登记app开发流程

    关于体温app,比较难的是获取定位信息,剩下的就是增删改查. 设计思路:首先布局一个添加页面,给每个元件添加id,之后在获取地点的EditText获取位置信息,在添加两个布局文件,体现在一个页面里用来 ...