NOIP2017 逛公园 题解报告 【最短路 + 拓扑序 + dp】
题目描述
策策同学特别喜欢逛公园。公园可以看成一张NNN个点MMM条边构成的有向图,且没有
 自环和重边。其中1号点是公园的入口,NNN号点是公园的出口,每条边有一个非负权值,
 代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从1号点进去,从NNN号点出来。
策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到NNN号点的最短路长为ddd,那么策策只会喜欢长度不超过d+Kd
 + Kd+K的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?
为避免输出过大,答案对PPP取模。
如果有无穷多条合法的路线,请输出−1。
输入输出格式
输入格式:
第一行包含一个整数 TTT,
 代表数据组数。
接下来TTT组数据,对于每组数据:
 第一行包含四个整数 N,M,K,PN,M,K,PN,M,K,P,每两个整数之间用一个空格隔开。
接下来MMM行,每行三个整数ai,bi,cia_i,b_i,c_iai,bi,ci,代表编号为ai,bia_i,b_iai,bi的点之间有一条权值为
cic_ici的有向边,每两个整数之间用一个空格隔开。
输出格式:
输出文件包含 TTT
 行,每行一个整数代表答案。
输入输出样例
说明
【样例解释1】
对于第一组数据,最短路为 3。 1 – 5, 1 – 2 – 4 – 5, 1 – 2 – 3 – 5 为 3 条合法路径。
【测试数据与约定】
对于不同的测试点,我们约定各种参数的规模不会超过如下
| 测试点编号 | TTT | NNN | MMM | KKK | 是否有0边 | 
|---|---|---|---|---|---|
| 1 | 5 | 5 | 10 | 0 | 否 | 
| 2 | 5 | 1000 | 2000 | 0 | 否 | 
| 3 | 5 | 1000 | 2000 | 50 | 否 | 
| 4 | 5 | 1000 | 2000 | 50 | 否 | 
| 5 | 5 | 1000 | 2000 | 50 | 否 | 
| 6 | 5 | 1000 | 2000 | 50 | 是 | 
| 7 | 5 | 100000 | 200000 | 0 | 否 | 
| 8 | 3 | 100000 | 200000 | 50 | 否 | 
| 9 | 3 | 100000 | 200000 | 50 | 是 | 
| 10 | 3 | 100000 | 200000 | 50 | 是 | 
对于 100%的数据, 1≤P≤109,1≤ai,bi≤N,0≤ci≤10001
 \le P \le 10^9,1 \le a_i,b_i \le N ,0 \le c_i \le 10001≤P≤109,1≤ai,bi≤N,0≤ci≤1000。
数据保证:至少存在一条合法的路线。
题解
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define fo(i,x,y) for (int i = (x); i <= (y); i++)
#define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
using namespace std;
const int maxn = 200005,maxm = 400005,maxk = 60,INF = 1000000000;
inline int read(){
int out = 0,flag = 1;char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();}
return out * flag;
}
int N,M,K,P;
int dS[maxn],dT[maxn],f[maxn][maxk],inde[maxn],id[maxn];
bool vis[maxn],zer[maxn];
int head[maxn],nedge = 0,h[maxn],ne = 0;
struct EDGE{int to,w,next;}edge[maxm],e[maxm];
inline void build(int u,int v,int w){
edge[nedge] = (EDGE) {v,w,head[u]}; head[u] = nedge++;
e[ne] = (EDGE) {u,w,h[v]}; h[v] = ne++;
if (!w) zer[u] = zer[v] = true,inde[v]++;
}
struct node{int u,d;};
inline bool operator <(const node& a,const node& b){return a.d > b.d;}
struct Node{int d,ti;}E[maxn];
inline bool cmp(const int& a,const int& b){return E[a].d == E[b].d ? E[a].ti < E[b].ti : E[a].d < E[b].d;}
void dijkstraS(){
REP(i,N) dS[i] = INF,vis[i] = false;
priority_queue<node> q;
dS[1] = 0;
q.push((node){1,dS[1]});
node u; int to;
while (!q.empty()){
u = q.top();
q.pop();
if (vis[u.u]) continue;
vis[u.u] = true;
Redge(u.u)
if (!vis[to = edge[k].to]){
if (dS[to] >= dS[u.u] + edge[k].w){
dS[to] = dS[u.u] + edge[k].w;
q.push((node){to,dS[to]});
}
}
}
}
void dijkstraT(){
REP(i,N) dT[i] = INF,vis[i] = false;
priority_queue<node> q;
dT[N] = 0;
q.push((node){N,dT[N]});
node u; int to;
while (!q.empty()){
u = q.top();
q.pop();
if (vis[u.u]) continue;
vis[u.u] = true;
for (int k = h[u.u]; k != -1; k = e[k].next)
if (!vis[to = e[k].to] && dT[to] > dT[u.u] + e[k].w){
dT[to] = dT[u.u] + e[k].w;
q.push((node){to,dT[to]});
}
}
}
bool tuopu(){
queue<int> q;
REP(i,N){
id[i] = i;
E[i].d = dS[i]; E[i].ti = 0;
if (zer[i] && !inde[i]){
q.push(i);
}
}
int u,to,cnt = 0;
while (!q.empty()){
u = q.front();
q.pop();
E[u].ti = ++cnt;
Redge(u) if (!edge[k].w){
inde[to = edge[k].to]--;
if (!inde[to]) q.push(to);
}
}
REP(i,N) if (zer[i] && inde[i] && dS[i] + dT[i] <= dT[1] + K) {printf("-1\n");return false;}
sort(id + 1,id + 1 + N,cmp);
//REP(i,N) cout<<id[i]<<' ';cout<<endl;
return true;
}
void solve(){
dijkstraS();
dijkstraT();
//REP(i,N) cout<<f[i][0]<<' ';cout<<endl;
if(!tuopu()) return;
f[1][0] = 1;
for (int j = 0; j <= K; j++)
for (int i = 1; i <= N; i++){
int u = id[i];
Redge(u){
int v = edge[k].to;
if (dS[u] + j + edge[k].w - dS[v] <= K){
f[v][dS[u] + j + edge[k].w - dS[v]] = (f[v][dS[u] + j + edge[k].w - dS[v]] + f[u][j]) % P;
}
}
}
int ans = 0;
for (int i = 0; i <= K; i++) ans = (ans + f[N][i]) % P;
printf("%d\n",ans);
}
void init(){
int a,b,c;
memset(f,0,sizeof(f));
N = read(); M = read(); K = read(); P = read();
ne = nedge = 0;
REP(i,N) head[i] = h[i] = -1,inde[i] = 0,zer[i] = false;
while (M--) {a = read(); b = read(); c = read(); build(a,b,c);}
}
int main()
{
int T = read();
while (T--){
init();
solve();
}
return 0;
}
NOIP2017 逛公园 题解报告 【最短路 + 拓扑序 + dp】的更多相关文章
- 【NOIP2017】逛公园 拆点最短路+拓扑(记忆化搜索
		题目描述 策策同学特别喜欢逛公园.公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策 ... 
- [NOIP2017]逛公园 题解
		我连D1T3都不会我联赛完蛋了 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 N 个点 M 条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口, N 号点是公园的出口,每条边有一个非负 ... 
- [NOIP2017] 逛公园 解题报告(DP)
		我很不想说 在我的AC代码上我打了表,但实在没有办法了.莫名的8,9个点RE.然而即便是打表...也花了我很久. 这大概是NOIP2017最难的题了,为了让不懂的人更容易理解,这篇题解会比较详细 我的 ... 
- [NOIP2017]逛公园  最短路+拓扑排序+dp
		题目描述 给出一张 $n$ 个点 $m$ 条边的有向图,边权为非负整数.求满足路径长度小于等于 $1$ 到 $n$ 最短路 $+k$ 的 $1$ 到 $n$ 的路径条数模 $p$ ,如果有无数条则输出 ... 
- [NOIP2017]逛公园 最短路图 拓扑序DP
		---题面--- 题解: 挺好的一道题. 首先我们将所有边反向,跑出n到每个点的最短路,然后f[i][j]表示从i号节点出发,路径长比最短路大j的方案数. 观察到,如果图中出现了0环,那么我们可以通过 ... 
- NOIP2017 Day1 T3 逛公园(最短路+拓扑排序+DP)
		神tm比赛时多清个零就有60了T T 首先跑出1起点和n起点的最短路,因为k只有50,所以可以DP.设f[i][j]表示比最短路多走i的长度,到j的方案数. 我们发现如果在最短路上的和零边会有后向性, ... 
- Luogu3953 NOIP2017逛公园(最短路+拓扑排序+动态规划)
		跑一遍dij根据最短路DAG进行拓扑排序,按拓扑序dp即可.wa了三发感觉非常凉. #include<iostream> #include<cstdio> #include&l ... 
- 【题解】NOIP2017逛公园(DP)
		[题解]NOIP2017逛公园(DP) 第一次交挂了27分...我是不是必将惨败了... 考虑这样一种做法,设\(d_i\)表示从该节点到n节点的最短路径,\(dp(i,k)\)表示从\(i\)节点 ... 
- [Luogu P3953] 逛公园 (最短路+拓扑排序+DP)
		题面 传送门:https://www.luogu.org/problemnew/show/P3953 Solution 这是一道神题 首先,我们不妨想一下K=0,即求最短路方案数的部分分. 我们很容易 ... 
随机推荐
- TPO-18 C2 Possible participation in a sociology project
			TPO-18 C2 Possible participation in a sociology project 第 1 段 1.listen to a conversation between a s ... 
- Unity Lighting - Light Probes 光照探针(十)
			Light Probes 光照探针 Only static objects are considered by Unity’s Baked or Precomputed Realtime GI s ... 
- String、StringBuffer、StringBuilder有什么区别
			区别 先说说String和StringBuffer/StringBuilder: String是标准的不可变类,是一个字符串常量池,并且声明的对象在方法中是唯一存在的. StringBuffer/St ... 
- fastCMS数据库相关操作类
			fastCMS针对数据库的操作有以下几个类: 1.[paging_Class]分页类 此类用于分页检索数据库内符合条件的记录 1) 支持百万级数据分页 2) 支持多种类型的SQL语法,比如 Left ... 
- 牛客网暑期ACM多校训练营(第一场):E-Removal(DP)
			链接:E-Removal 题意:给出序列 s1, s2, ..., sn ,1<=s[i]<=10.问删除m个数后,有多少种不同的序列. 题解:定义dp[i][j]代表长度为i,最末尾的数 ... 
- Linux系统服务(daemon)(鸟哥Linux私房菜笔记)
			Linux系统服务(daemon) 一.SystemV的init管理机制(脚本式启动)1.服务启动分类stand alone 独立启动模式super daemon 总管程序 2.服务的启动.关闭与观察 ... 
- Python的sys.argv使用说明
			刚开始使用这个参数的时候,很不明白其含义.网上搜索很多都是贴的官网上面的一则实例,说看懂,就明白.可是,我看不懂.现在在回头看这个参数使用,并不是很麻烦. 举几个小例子就明白了. 创建一个脚本,内容如 ... 
- 使用qemu启动dd制作的img镜像
			1. 准备工作 应用场景 在需要单机取证时,需要在不影响对象业务的情况下进行取证或分析,可以使用dd 对目标服务器进行镜像,生成img文件,镜像可以通过winhex进行静态分析.但是想要动态分析服务器 ... 
- visual studio 2010 和 VSS(Visual SourceSafe)的连接使用
			visual studio 2010 和 VSS(Visual SourceSafe)的连接使用 1. 在visual vstudio中选择使用VSS插件: 2. 使用VSS进行源码管理: ... 
- ES6的新特性(5)——数值的扩展
			数值的扩展 二进制和八进制表示法 ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示. 0b111110111 === 503 // true 0o767 === ... 
