洛谷刷题笔记——P3953 [NOIP2017 提高组] 逛公园
参考资料:
- 洛谷
_风休住
大佬的题解
[NOIP2017 提高组] 逛公园
题目描述
策策同学特别喜欢逛公园。公园可以看成一张 NNN 个点 MMM 条边构成的有向图,且没有 自环和重边。其中 111 号点是公园的入口,NNN 号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从 111 号点进去,从 NNN 号点出来。
策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果 111 号点 到 NNN 号点的最短路长为 ddd,那么策策只会喜欢长度不超过 d+Kd + Kd+K 的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?
为避免输出过大,答案对 PPP 取模。
如果有无穷多条合法的路线,请输出 −1-1−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
样例输入 #1
2
5 7 2 10
1 2 1
2 4 0
4 5 2
2 3 2
3 4 1
3 5 2
1 5 3
2 2 0 10
1 2 0
2 1 0
样例输出 #1
3
-1
提示
【样例解释1】
对于第一组数据,最短路为 333。 1→5,1→2→4→5,1→2→3→51\to 5, 1\to 2\to 4\to 5, 1\to 2\to 3\to 51→5,1→2→4→5,1→2→3→5 为 333 条合法路径。
【测试数据与约定】
N≤105N \leq 10^5N≤105,M≤2×105M \leq 2\times10^5M≤2×105,K≤50K \leq 50K≤50。
思路
最短路+dp
本题需要建正、反两张图,正图用于求最短路,反图用于记忆化搜索和dp。
由于本题目中约定每条边的权值≥0\geq 0≥0,所以图中不存在负环,可以在正图上运行迪杰斯特拉算法求出起点到所有结点的最短距离,保存在数组d[]
中,其中,d[i]
表示起点到结点i
的最短距离。
然后就到了本题的精髓之处:动态规划。定义状态dp[i][k]
表示:从起点到结点i
的长度恰好为d[i]+k
的路径的条数。显然,问题所求的答案为:dp[n][0] + dp[n][1] + ... + dp[n][K]
。然后考虑状态之间的转移。假设在正图中有一条有向边(v,u)(v,u)(v,u),其权值为www,则我们可以通过状态dp[v][x]
转移到状态dp[u][k]
。对于结点u, v
有如下关系:
d[u]+x+w=d[v]+kd[u]+x+w=d[v]+kd[u]+x+w=d[v]+k
于是有:
x=d[v]−d[u]+k−wx=d[v]-d[u]+k-wx=d[v]−d[u]+k−w
由此,我们得到状态转移方程:
dp[u][k]=∑(v,u)∈G1dp[u][d[v]−d[u]+k−w]dp[u][k]=\sum_{(v,u)\in G_1}dp[u][d[v]-d[u]+k-w]dp[u][k]=(v,u)∈G1∑dp[u][d[v]−d[u]+k−w]
在反图上进行记忆化搜索即可实现动态规划。
然后我们考虑输出为-1
的情况:分析题目可知,只有当图中存在零环,且该零环中某一结点出现在某条合法路径上时,最终输出才为-1
。我们可以在记忆化搜索的过程中找出零环。假设当前要求dp[i][k]
,我们沿着返图进行记忆化搜索,在得到最终的dp[i][k]
之前,我们如果回到了dp[i][k]
,说明结点i
在一个零环上。
我们还需要考虑动态规划的边界条件。首先,对于任意一个点i
,当k<0k<0k<0时,dp[i][k]
一定为0
。再者,我们在进行真正的记忆化搜索前,需要先记忆化搜索dp[1][0],如果在搜索的过程中发现零环,则直接输出-1
即可,否则令dp[1][0]
为1
。
完整代码
#include<bits/stdc++.h>
#define maxn 200005
using namespace std;int T;
int n, m, K, p;
int cnt1 = 0, cnt2 = 0;
int head1[maxn], head2[maxn];
int d[maxn];
bool vis[maxn];
int dp[maxn][55];
bool ins[maxn][55];
bool infty;
int ans;struct EDGE{int to;int v;int next;
}edge1[maxn], edge2[maxn];void addEdge1(int fr, int to, int v){cnt1++;edge1[cnt1].to = to;edge1[cnt1].v = v;edge1[cnt1].next = head1[fr];head1[fr] = cnt1;
}void addEdge2(int fr, int to, int v){cnt2++;edge2[cnt2].to = to;edge2[cnt2].v = v;edge2[cnt2].next = head2[fr];head2[fr] = cnt2;
}struct cmp{bool operator()(pair<int, int>p1, pair<int, int>p2){return p1.second>p2.second;}
};void dij(int i){memset(d, 37, sizeof(d));priority_queue<pair<int, int>, vector<pair<int, int>>, cmp> q;q.push(make_pair(i, 0));d[i] = 0;while(!q.empty()){pair<int, int> p = q.top(); q.pop();int pos = p.first;if(vis[pos]) continue;vis[pos] = 1;for(int i=head1[pos];i!=0;i=edge1[i].next){int to = edge1[i].to, v = edge1[i].v;if(vis[to]) continue;if(d[to]>d[pos]+v){d[to] = d[pos]+v;q.push(make_pair(to, d[to]));}}}
}void dfs(int u, int k){if(infty) return;if(k<0) return;if(ins[u][k]){infty = true;return;}if(dp[u][k]!=0) return;ins[u][k] = true;int res = 0;for(int i=head2[u];i!=0;i=edge2[i].next){int to = edge2[i].to, v = edge2[i].v;int x = d[u]-d[to]+k-v;dfs(to, x);if(x>=0) res += dp[to][x];res %= p;}dp[u][k] = res;ins[u][k] = false;
}void init(){cnt1 = cnt2 = 0;memset(head1, 0, sizeof(head1));memset(head2, 0, sizeof(head2));memset(edge1, 0, sizeof(edge1));memset(edge2, 0, sizeof(edge2));memset(d, 0, sizeof(d));memset(vis, 0, sizeof(vis));memset(ins, 0, sizeof(ins));memset(dp, 0, sizeof(dp));infty = false;ans = 0;
}int main(){cin>>T;while(T--){init();cin>>n>>m>>K>>p;for(int i=0;i<m;i++){int a, b, c;cin>>a>>b>>c;addEdge1(a, b, c);addEdge2(b, a, c);}dij(1);dfs(1, 0);dp[1][0] = 1;if(infty){cout<<-1<<'\n';continue;}for(int i=0;i<=K;i++){dfs(n, i);if(infty) break;ans += dp[n][i];ans %= p;}if(infty) cout<<-1<<'\n';else cout<<ans<<'\n'; }return 0;
}
洛谷刷题笔记——P3953 [NOIP2017 提高组] 逛公园相关推荐
- 洛谷 P3953 [NOIP2017 提高组] 逛公园
开始刷题单啦~,这部分的洛谷好题作为个人训练记录和以后复习用,有兴趣的可以一起做做 题目链接:P3953 [NOIP2017 提高组] 逛公园 题意都是中文就不翻译了 题解:这是一道记忆化+搜索的题目 ...
- 洛谷刷题笔记 地球人口承载力估计
题目描述 假设地球上的新生资源按恒定速度增长.照此测算,地球上现有资源加上新生资源可供 x 亿人生活 a 年,或供 y 亿人生活 b 年. 为了能够实现可持续发展,避免资源枯竭,地球最多能够养活多少亿 ...
- 洛谷刷题笔记 乘方计算
题目描述 给出一个整数 a 和一个正整数 n,求乘方 a^n. 输入格式 一行,包含两个整数 a 和 n.-−1000000≤a≤1000000,1≤n≤10000. 输出格式 一个整数,即乘方结果. ...
- 洛谷刷题笔记 整理药名
题目描述 医生在书写药品名的时候经常不注意大小写,格式比较混乱.现要求你写一个程序将医生书写混乱的药品名整理成统一规范的格式,即药品名的第一个字符如果是字母要大写,其他字母小写. 如将 ASPIRIN ...
- 洛谷刷题笔记 求一元二次方程
题目描述 利用公式 : 求一元二次方程 ax^2+bx+c=0的根,其中 a 不等于 0.结果要求精确到小数点后 5 位. 输入格式 输入一行,包含三个浮点数 a,b,c(它们之间以一个空格分开),分 ...
- 洛谷刷题笔记 打印 ASCII 码
题目描述 输入一个除空格以外的可见字符,输出其 ASCII 码. 输入格式 一个除空格以外的可见字符. 输出格式 一个十进制整数,即该字符的 ASCII 码. 输入输出样例 输入 #1复制 A 输出 ...
- 洛谷刷题笔记 奥运奖牌计数
题目描述 2008年北京奥运会,A 国的运动员参与了 n 天的决赛项目 (1≤n≤100).现在要统计一下 A 国所获得的金.银.铜牌数目及总奖牌数.输入第 1行是 A 国参与决赛项目的天数 n,其后 ...
- 洛谷刷题笔记 分糖果
题目描述 某个幼儿园里,有 5位小朋友编号依次为 1,2,3,4,5 他们按照自己的编号顺序围坐在一张圆桌旁.他们身上有若干糖果,现在他们玩一个分糖果游戏.从 1 号小朋友开始,将自己的糖果均分成 3 ...
- 洛谷刷题C语言:距离函数、闰年展示、计算阶乘、猴子吃桃、培训
记录洛谷刷题QAQ 一.[深基7.例1]距离函数 题目描述 给出平面坐标上不在一条直线上三个点坐标 (x1,y1),(x2,y2),(x3,y3)(x_1,y_1),(x_2,y_2),(x_3,y_ ...
- 洛谷刷题C语言:陶瓷项链、Cow Gymnastics B、Where Am I? B、Hello, 2020!、SIR 模型
记录洛谷刷题C语言 一.[NOI2000] 瓷片项链 题目描述 原始部落用一种稀有的泥土烧制直径相同的圆瓷片并串成项链,串的时候沿瓷片的直径方向顺次连接,瓷片之间没有空隙也不重叠,一条项链至少由一个瓷 ...
最新文章
- 超级计算机的缺点,超级计算机也无法算完圆周率,反而会死机?说出来你一定不会相信...
- QML自定义图表图例
- [转]JavaScript构造函数及原型对象
- 幼儿园带括号算式口诀_这么全的小学数学速算技巧、口诀不多见,教给孩子挺不错!...
- eureka 之前的服务如何关闭_干货分享 | 服务注册中心Spring Cloud Eureka部分源码分析...
- 支付宝小程序公测!教程新鲜出炉
- 安卓Android面试题大全
- php 去掉后导字符,PHP去除字符串最后一个字符的三种方法实例
- 怎么做301永久重定向
- Xamarin学习笔记
- Sketch for mac v78 矢量绘图软件
- VMware Tools安装步骤(windows10)
- C语言/C++项目——黄金矿工
- flink流处理示例开发
- 小程序影藏溢出的gif_视频转gif怎么弄?视频片段转动图 将影视片段制作成微信表情包的方法~...
- 2017年软考程序员下午题第二题
- IE7,IE8与IE6兼容路上的痛苦
- java scanner 读取文件_Java读取文本文件
- 【编程基础の基础】“#define _GNU_SOURCE“或是在编译时“-D _GNU_SOURCE“代表了什么?有什么用
- ubuntu 硬盘管理工具