【问题描述】

小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. Python实现两已知排好序的列表合并成一个排好序的列表

    #方法0.5--- lst1 = [1, 3, 7, 9, 12] lst2 = [4, 8, 9, 13, 15, 19] def merge(a, b): c = [] h = j = 0 whi ...

  2. _bzoj1911 [Apio2010]特别行动队【斜率优化dp】

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1911 裸的斜率优化dp. #include <cstdio> const int ...

  3. D Tree HDU - 4812

    https://vjudge.net/problem/HDU-4812 点分就没一道不卡常的? 卡常记录: 1.求逆元忘开longlong 2.把solve中分离各个子树的方法,由“一开始全部加入,处 ...

  4. 水题 Codeforces Round #303 (Div. 2) A. Toy Cars

    题目传送门 /* 题意:5种情况对应对应第i或j辆车翻了没 水题:其实就看对角线的上半边就可以了,vis判断,可惜WA了一次 3: if both cars turned over during th ...

  5. 牛客练习赛25-A-因数个数和

    题目描述 q次询问,每次给一个x,问1到x的因数个数的和. 输入描述: 第一行一个正整数q:接下来q行,每行一个正整数x 输出描述: 共q行,每行一个正整数表示答案 输入 4 1 2 3 10 输出 ...

  6. subline应用之技巧

    看很多人代码编辑器都用subline,一了解这货也跨平台.支持代码提示自动补全.支持python.语法高亮.最关键的是支持列编辑(原来以为只有ue有此功能),那就果断下载使用,挺好! 列编辑:首先用鼠 ...

  7. 关于提示replication性能

    关于GTIDs的二进制日志:gtid_next: 下一个事务的编号,是master传给slave的 如SET @@SESSION.GTID_NEXT= 'c09756b8-a7e7-11e5-9468 ...

  8. Apache Kylin Cube 的存储

    不多说,直接上干货! 简单的说Cuboid的维度会映射为HBase的Rowkey,Cuboid的指标会映射为HBase的Value. Cube映射成HBase存储 如上图原始表所示:Hive表有两个维 ...

  9. [转]MVC 检测用户是否已经登录

    本文转自:http://blog.csdn.net/jayzai/article/details/41252137 当我们访问某个网站的时候需要检测用户是否已经登录(通过Session是否为null) ...

  10. Dapper系列之三:Dapper的事务修改与删除

    Dapepr的Update和Delete Dapper入门Dapper查询 上两篇文章我们介绍Dapper中添加和查询.本篇文章我们继续讲解修改和删除....如果本篇文章看不懂,请看阅读上两篇Dapp ...