原文链接https://www.cnblogs.com/zhouzhendong/p/CF-Gym100783H.html

题目传送门 - CF-Gym100783H

题意

  给定一个 $n$ 个节点 $P$ 条带权边的无向图,有 $m$ 个特殊点。给定开始点 $X$ 和结束点 $Y$ 。

  现在请你求一个 $k$ ,使得令所有边的权值都加上 $k$ 之后,$X$~$Y$ 的最短路经过且仅经过特殊点,不能有其他的最短路途中任意一个节点不是特殊点。

  问满足条件的 $k$ 最大是多少。如果 $k=\infty$ ,则输出 $Infinity$ 。如果不存在这样的 $k$ 则输出 $Impossible$ 。否则输出 $k$ 的值。

  $n,m\leq 1000,\ \ \ \ \ \ P\leq 10000,\ \ \ \ \ 1\leq X,Y\leq n$

题解

  我们记原图为 $g1$,记仅包含特殊点和连接他们的边的图为 $g2$ 。

  对于 $g1$ 和 $g2$ 我们分别求出 $X$ 走 $i$ 步到 $Y$ 的最短路(按照原来的边权)。这个可以 nm simple dp 。

  我们记 $g1$ 和 $g2$ 中最多走 $i$ 步从 $S$ 到 $T$ 的最短路值分别为 $v1[i]$ 和 $v2[i]$ 。

  然后我们枚举一个 $i$ 并求走最多 $i$ 步到达 $T$ 在 $g_1$ 中的最短路值为全局最短路的 $k$ 的取值范围。

  这个取值范围如何求?

  我们得满足走 $i$ 步是最短的。所以:

  对于 $j=i$ : $v1[i]=v2[j]$

  对于 $j>i$ : $v1[i]+ki\leq v1[j]+kj\Longrightarrow v1[i]-v1[j]\leq k(j-i)\Longrightarrow k\geq \cfrac{v1[i]-v1[j]}{j-i}$

  对于 $j<i$ : $v1[i]+ki\leq v1[j]+kj\Longrightarrow v1[j]-v1[i]\geq k(i-j)\Longrightarrow k\leq \cfrac{v1[j]-v1[i]}{i-j}$

  如果满足上述条件的 $k$ 存在,那么我们可以用满足上述条件的最大 $k$ 值来更新答案。

  细心的你可能已经发现了,我这个做法忽略了可能存在的经过非特殊点的最短路的情况。

  要搞定这个东西其实很简单。我们取一个略大于 $n$ 的值 : $1024$,对于每一个初始边权 $v$,如果它连接的是两个特殊点,那么令 $v^\prime =1024v$ 否则 $v^\prime = 1024v+1$ 。

  这样有什么用呢?如果存在走 $j$ 步且经过非特殊点的最短路,那么 $dis \mod 1024 < j$ 。

  这个相等权值的情况要特别注意。别忘了在求之前 $k$ 的取值范围中也要加上关于这个的特判,微调一下 $k$ 的取值范围。

  建议提前判掉 $Infinity$ 的情况和部分 $Impossible$ 的情况。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1005;
const LL INF=1LL<<62;
int n,m,S,T;
int owned[N];
struct Gragh{
static const int M=20005;
int cnt,x[M],y[M],nxt[M],fst[N];
LL z[M];
void clear(){
cnt=0;
memset(fst,0,sizeof fst);
}
void add(int a,int b,int c){
y[++cnt]=b,x[cnt]=a,z[cnt]=c,nxt[cnt]=fst[a],fst[a]=cnt;
}
}g,g2;
void Get_owned(){
memset(owned,0,sizeof owned);
int m,x;
scanf("%d",&m);
while (m--)
scanf("%d",&x),owned[x]=1;
}
LL v1[N],v2[N];
LL dis[N][N];
void Getv(Gragh &g,LL v[]){
for (int i=0;i<n;i++)
for (int j=1;j<=n;j++)
dis[i][j]=INF;
dis[0][S]=0;
for (int i=0;i<n-1;i++)
for (int j=1;j<=g.cnt;j++)
dis[i+1][g.y[j]]=min(dis[i+1][g.y[j]],dis[i][g.x[j]]+g.z[j]);
for (int i=0;i<n;i++)
v[i]=dis[i][T];
for (int i=1;i<n;i++)
v[i]=min(v[i-1],v[i]);
}
bool check1(){
return v2[n-1]<INF;
}
bool check2(){
int p1=0,p2=0;
while (v1[p1]==INF)
p1++;
while (v2[p2]==INF)
p2++;
return p1==p2&&v1[p1]==v2[p2];
}
LL k1[N],k2[N];
LL solve3(){
LL ans=-1,k=0;
for (int i=n-1;i>0;i--){
if (v1[i]!=v2[i]||v2[i]==INF)
continue;
LL Min=1,Max=INF;
// v1[i]+k*i <= v1[j]+k*j
// v1[i]-v1[j] <= k*(j-i)
// k >= (v1[i]-v1[j]) / (j-i)
for (int j=i+1;j<n;j++){
LL now=((v1[i]>>10)-(v1[j]>>10)+j-i-1)/(j-i);
if ((v1[j]&1023LL)!=j&&now*(j-i)==((v1[i]>>10)-(v1[j]>>10)))
now++;
Min=max(Min,now);
}
// v1[i]+k*i <= v1[j]+k*j
// k <= (v1[j]-v1[i])/ (i-j)
for (int j=0;j<i;j++){
if (v1[j]==INF)
continue;
LL now=((v1[j]>>10)-(v1[i]>>10))/(i-j);
if ((v1[j]&1023LL)!=j&&now*(i-j)==((v1[j]>>10)-(v1[i]>>10)))
now--;
Max=min(Max,now);
}
if (Min<=Max)
ans=max(ans,Max);
}
return ans;
}
int main(){
while(~scanf("%d%d%d%d",&n,&m,&S,&T)){
g.clear(),g2.clear();
for (int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
g.add(a,b,c);
g.add(b,a,c);
}
Get_owned();
for (int i=1;i<=m*2;i++){
g.z[i]<<=10;
if (owned[g.x[i]]&&owned[g.y[i]]){
g.z[i]++;
g2.add(g.x[i],g.y[i],g.z[i]);
}
}
Getv(g,v1);
Getv(g2,v2);
if (!check1()){
puts("Impossible");
continue;
}
if (check2()){
puts("Infinity");
continue;
}
LL ans=solve3();
if (ans<0)
puts("Impossible");
else
printf("%lld\n",ans);
}
return 0;
}

  

Codeforces Gym100783H 最短路 其他的更多相关文章

  1. CodeForces 300C 最短路

    A Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Pr ...

  2. President's Path CodeForces - 416E (最短路,计数)

    大意: 给定无向图, 求任意两点间所有最短路经过的边数 刚开始想先用floyd跑出最短路, 然后在DAG上DP, 交了1发, 发现会算重复 贴一下题解的做法 #include <iostream ...

  3. codeforces 757F - 最短路DAG+灭绝树

    Description 给定一个n个点,m条边的带权无向图,和起点S.请你选择一个点u(u!=S),使得在图中删掉点u 后,有尽可能多的点到S的最短距离改变. Solution 先建出最短路DAG,在 ...

  4. Codeforces 1076D——最短路算法

    题目 给你一个有n个顶点.m条边的无向带权图.需要擦除一些边使得剩余的边数不超过k,如果一个点在原始图到顶点1的最短距离为d,在删边后的图中到顶点的最短距离仍是d,则称这种点是 good.问如何删边, ...

  5. Codeforces 1149D 最短路 状压DP

    题意及思路:https://blog.csdn.net/yzyyylx/article/details/90145400 这题主要巧妙在分析了最短路算法的性质,得出大小小于等于3的连通块一定不会被再次 ...

  6. Codeforces 1163F 最短路 + 线段树 (删边最短路)

    题意:给你一张无向图,有若干次操作,每次操作会修改一条边的边权,每次修改后输出1到n的最短路.修改相互独立. 思路:我们先以起点和终点为根,找出最短路径树,现在有两种情况: 1:修改的边不是1到n的最 ...

  7. CodeForces - 449B 最短路(迪杰斯特拉+堆优化)判断最短路路径数

    题意: 给出n个点m条公路k条铁路. 接下来m行 u v w      //u->v 距离w 然后k行 v w         //1->v 距离w 如果修建了铁路并不影响两点的最短距离, ...

  8. Codeforces Beta Round #77 (Div. 1 Only) C. Volleyball (最短路)

    题目链接:http://codeforces.com/contest/95/problem/C 思路:首先dijkstra预处理出每个顶点到其他顶点的最短距离,然后如果该出租车到某个顶点的距离小于等于 ...

  9. Codeforces Round #130 (Div. 2) C - Police Station 最短路+dp

    题目链接: http://codeforces.com/problemset/problem/208/C C. Police Station time limit per test:2 seconds ...

随机推荐

  1. Java对数

    java对数 先看看Java源码里的对数函数(在Java.lang.Math里) 方法1:log() 作用:返回以自然常数e为底数的对数值 说明: e ≍ 2.71828 18284 59045 23 ...

  2. winform无需安装pdf阅读器打开pdf文件

    控件来源:http://www.o2sol.com/pdfview4net/download.htm (使用版本:2016年8月31号更新版) 备份链接: https://pan.baidu.com/ ...

  3. 关于《common-net》的ftp上传

    1:jar的maven的引用: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http ...

  4. Confluence 6 修改日志文件的大小数量和级别

    修改日志文件的大小和数量 在默认的情况下,Confluence 将会保持 5 个日志文件,每一个日志文件的大小超过 20 MB 的时候将会被重写. 你可以修改默认日志文件的大小和数量,通过编辑 < ...

  5. Nginx详解二十五:Nginx架构篇之Nginx常见的问题

    Nginx常见的问题 1.相同server_name多个虚拟主机优先级访问,是按读取文件的优先级来排序 在/opt/app/下准备3个code文件夹,下面放入3个html文件,里面的内容分别是code ...

  6. MySQL基于ROW格式的数据恢复

    大家都知道MySQL Binlog 有三种格式,分别是Statement.Row.Mixd.Statement记录了用户执行的原始SQL,而Row则是记录了行的修改情况,在MySQL 5.6以上的版本 ...

  7. Java SimpleDateFormat 中英文时间格式化转换

    2015年08月29日 17:37:43 阅读数:32459 SimpleDateFormat是一个以与语言环境有关的方式来格式化和解析日期的具体类.它允许进行格式化(日期 -> 文本).解析( ...

  8. 论文阅读笔记二十六:Fast R-CNN (ICCV2015)

    论文源址:https://arxiv.org/abs/1504.08083 参考博客:https://blog.csdn.net/shenxiaolu1984/article/details/5103 ...

  9. Linux下安装软件命令详解

    ---------------------------------------------------------------- 或许你对于linux还不够了解,但是一旦你步入公司后,你就会发现lin ...

  10. 创建Python虚拟环境

    以window为例: 安装完python后, 打开cmd, 命令行输入: pip install virtualenv ,安装过程见截图 进入你想安装虚拟环境的目录, 命令行输入: virtualen ...