【问题描述】

小P和小R在玩一款益智游戏。游戏在一个正权有向图上进行。

小P控制的角色要从A点走最短路到B点,小R控制的角色要从C点走最短路到D点。

一个玩家每回合可以有两种选择,移动到一个相邻节点或者休息一回合。

假如在某一时刻,小P和小R在相同的节点上,那么可以得到一次特殊奖励,但是在每个节点上最多只能得到一次。

求最多能获得多少次特殊奖励。

【输入格式】

第一行两个整数n,m表示有向图的点数和边数。

接下来m行每行三个整数xi,yi,li,表示从xi到yi有一条长度为li的边。

最后一行四个整数A,B,C,D,描述小P的起终点,小R的起终点。

【输出格式】

输出一个整数表示最多能获得多少次特殊奖励。若小P不能到达B点或者小R不能到达D点则输出-1。

【样例输入输出】

game.in

game.out

5 5

1 2 1

2 3 2

3 4 4

5 2 3

5 3 5

1 3 5 4

2

【数据规模】

对于30%的数据,满足n≤50

对于60%的数据,满足n≤1000,m≤5000

对于100%的数据,满足n≤50000,m≤200000,1≤li≤500000000

【题解】

为了处理出最短路径涉及的块,跑4遍最短路,也就是在原图和反向图上跑最短路对AB和CD各做1次

之后标记两个最短路网的边,被标记两次的就是两个人能相遇的边

对这些被标记的边建一个新图,跑拓扑排序+Dp找DAG的最长路,最长路经即为解

#include <queue>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define oo 0x7fffffff - 1
#define max(a, b) ((a) > (b) ? (a) : (b))
using namespace std;
inline int read()
{
int c = getchar(), x = 0;
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + c - '0', c = getchar();
return x;
}
int ans, n, m, A, B, C, D, cnt, ncnt, fcnt, h[50003], nh[50003], fh[50003], d1[50003], d2[50003], hash[200003], du[50003], Q[50003], f[50003];
struct pt {int v, w, ne;} a[200003], na[200003], fa[200003];
struct ed {int u, v, w;} e[200003];
struct abcd {
int fir, sec;
bool operator < (const abcd oth) const {return sec > oth.sec;} };
priority_queue<abcd> q;
bool mark[50003];
inline void link(int u, int v, int w) {a[++cnt].v = v, a[cnt].w = w, a[cnt].ne = h[u], h[u] = cnt;}
inline void nlink(int u, int v, int w) {na[++ncnt].v = v, na[ncnt].w = w, na[ncnt].ne = nh[u], nh[u] = ncnt;}
inline void flink(int u, int v, int w) {fa[++fcnt].v = v, fa[fcnt].w = w, fa[fcnt].ne = fh[u], fh[u] = fcnt;}
void dijkstra(int x, int d[], pt a[], int h[])
{
for(int i = 1; i <= n; ++i) d[i] = oo, mark[i] = 0;
d[x] = 0; q.push((abcd){x, 0});
while(!q.empty())
{
int now = q.top().fir; q.pop();
if(mark[now]) continue;
mark[now] = 1;
for(int j = h[now]; j; j = a[j].ne)
if(!mark[a[j].v] && d[a[j].v] > d[now] + a[j].w)
{
d[a[j].v] = d[now] + a[j].w;
q.push((abcd){a[j].v, d[a[j].v]});
}
}
}
bool preced()
{
dijkstra(A, d1, a, h);
dijkstra(B, d2, na, nh);
if(d1[B] == oo || d2[A] == oo) return 0;
for(int j = 1; j <= m; ++j) if(d1[e[j].u] + e[j].w + d2[e[j].v] == d1[B]) ++hash[j];
dijkstra(C, d1, a, h);
dijkstra(D, d2, na, nh);
if(d1[D] == oo || d2[C] == oo) return 0;
for(int j = 1; j <= m; ++j)
{
if(d1[e[j].u] + e[j].w + d2[e[j].v] == d1[D]) ++hash[j];
if(hash[j] == 2) {flink(e[j].u, e[j].v, e[j].w); ++du[e[j].v];}
}
return 1;
}
void sortdp()
{
for(int i = 1; i <= n; ++i) {f[i] = 1; if(!du[i]) Q[++Q[0]] = i;}
for(int i = 1; i <= Q[0]; ++i)
{
int now = Q[i];
for(int j = fh[now]; j; j = fa[j].ne)
{
f[fa[j].v] = max(f[fa[j].v], f[now] + 1);
ans = max(ans, f[fa[j].v]);
--du[fa[j].v];
if(!du[fa[j].v]) Q[++Q[0]] = fa[j].v;
}
}
printf("%d\n", ans);
}
int main()
{
freopen("game.in", "r", stdin), freopen("game.out", "w", stdout);
n = read(), m = read();
for(int i = 1; i <= m; ++i)
{
e[i].u = read(), e[i].v = read(), e[i].w = read();
link(e[i].u, e[i].v, e[i].w);
nlink(e[i].v, e[i].u, e[i].w);
}
A = read(), B = read(), C = read(), D = read();
if(preced()) sortdp();
else puts("-1");
fclose(stdin), fclose(stdout);
return 0;
}

  

[第一波模拟\day3\T3]{益智游戏}(game.cpp)的更多相关文章

  1. [第一波模拟\day3\T2]{独立集}(bubble.cpp)

    [问题描述] 有一天,一个名叫顺旺基的程序员从石头里诞生了.又有一天,他学会了冒泡排序和独立集.在一个图里,独立集就是一个点集,满足任意两个点之间没有边.于是他就想把这两个东西结合在一起.众所周知,独 ...

  2. 【2018.06.26NOIP模拟】T3节目parade 【支配树】*

    [2018.06.26NOIP模拟]T3节目parade 题目描述 学校一年一度的学生艺术节开始啦!在这次的艺术节上总共有 N 个节目,并且总共也有 N 个舞台供大家表演.其中第 i 个节目的表演时间 ...

  3. 雅礼 noip2018 模拟赛 day3 T3

    典型树形dp 这里,我们应该看到一些基本性质: ①:如果这个边不能改(不是没有必要改),我们就不改,因为就算改过去还要改回来,显然不是最优的 注意:"不能改"是指边的性质和要求的相 ...

  4. [第一波模拟\day1\T2]{分班}(divide.cpp)

    [题目描述] 小N,小A,小T又大了一岁了. 现在,他们已经是高二年级的学生了.众所周知,高二的小朋友是要进行文理科分班考试的,这样子的话,三个好朋友说不定就会不分在一个班. 于是三个人决定,都考平均 ...

  5. [第一波模拟\day2\T1] {病毒分裂}(split.cpp)

    [题目描述] A 学校的实验室新研制出了一种十分厉害的病毒.由于这种病毒太难以人工制造了,所以专家们在一开始只做出了一个这样的病毒.这个病毒被植入了特殊的微型芯片,使其可以具有一些可编程的特殊性能.最 ...

  6. NOIP欢乐模拟赛 T3 解题报告

    3.小澳的葫芦 (calabash.cpp/c/pas) [题目描述] 小澳最喜欢的歌曲就是<葫芦娃>. 一日表演唱歌,他尽了洪荒之力,唱响心中圣歌. 随之,小澳进入了葫芦世界. 葫芦世界 ...

  7. 20161005 NOIP 模拟赛 T3 解题报告

    subset 3.1 题目描述 一开始你有一个空集,集合可以出现重复元素,然后有 Q 个操作 1. add s 在集合中加入数字 s. 2. del s 在集合中删除数字 s.保证 s 存在 3. c ...

  8. 神奇的Noip模拟试题 T3 科技节 位运算

    3 科技节 (scifest.pas/.c/.cpp) [问题描述] 一年一度的科技节即将到来.同学们报名各项活动的名单交到了方克顺校长那,结果校长一看皱了眉头:这帮学生热情竟然如此高涨,每个人都报那 ...

  9. ztz11的noip模拟赛T3:评分系统

    代码: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> ...

随机推荐

  1. sql server 获取数据字段(表的字段和类型信息)

    获取数据字段(表的字段和类型信息) SELECT 表名= then d.name else '' end, 表说明= then isnull(f.value,'') else '' end, 字段序号 ...

  2. bzoj1024 [SCOI2009]生日快乐【dfs】

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1024 普通的深搜. #include <cstdio> #include < ...

  3. Brush (III) LightOJ - 1017

    Brush (III) LightOJ - 1017 题意:有一些点,每刷一次可以将纵坐标在区间(y1,y1+w)范围内的所有点刷光,y1为任何实数.最多能刷k次,求最多共能刷掉几个点. 先将点按照纵 ...

  4. double发生精度丢失的解决办法

    发生精度丢失的原因: 个人理解:机器在运行时,使用2进制形式的计数方式,而我们日常生活中的计算是10进制的,对于整数的加减乘除,double还能适用,但是对于有小数的,则容易发生精度丢失,即用2进制表 ...

  5. 转 做了两款数据库监控工具(mysql and nosql),打算在近期开源

    http://www.cnblogs.com/leefreeman/p/7297549.html 监控指标:https://www.linuxidc.com/Linux/2015-08/122009. ...

  6. Android开发-浅谈架构(二)

    写在前面的话 我记得有一期罗胖的<罗辑思维>中他提到 我们在这个碎片化 充满焦虑的时代该怎么学习--用30%的时间 了解70%该领域的知识然后迅速转移芳草鲜美的地方 像游牧民族那样.原话应 ...

  7. Dapper系列之二:Dapper的事务查询

    Dapepr讲解 上篇文章我们介绍了,什么是Dapepr,有什么好处,性能的对比,还有多表多数据添加操作(事务的封装)等等.本篇文章我们继续讲解.....如果本篇文章看不懂,请看我上一篇文章:Dape ...

  8. CF985D Sand Fortress

    思路: 很奇怪的结论题,不好想.参考了http://codeforces.com/blog/entry/59623 实现: #include <bits/stdc++.h> using n ...

  9. Android手机屏幕投射到电脑神器Vysor

    做android开发的,经常要把手机屏幕投射到电脑,用来演示.普遍的解决方案是360或者豌豆荚的演示功能,缺点是延迟非常厉害,大概有3秒左右,非常影响演示效果.以下介绍Vysor,几乎0延迟,能与手机 ...

  10. Python调用Java代码部署及初步使用

    Python调用Java代码部署: jpype下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#jpype 下载的时候需要使用Chrome浏览器进行下载 ...