spfa+dp+反向spfa 洛谷  P3953 逛公园

2023-11-10 02:48
文章标签 洛谷 反向 逛公园 p3953

本文主要是介绍spfa+dp+反向spfa 洛谷  P3953 逛公园,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目描述

策策同学特别喜欢逛公园。公园可以看成一张 NN 个点 MM 条边构成的有向图,且没有自环和重边。其中1号点是公园的入口, NN 号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花的时间。

策策每天都会去逛公园,他总是从1号点进去,从 NN 号点出来。

策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 NN 号点的最短路长为 dd ,那么策策只会喜欢长度不超过 d+ Kd+K 的路线。

策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?

为避免输出过大,答案对 PP 取模。

如果有无穷多条合法的路线,请输出−1

输入输出格式

输入格式:

第一行包含一个整数 TT , 代表数据组数。

接下来 TT 组数据,对于每组数据:第一行包含四个整数 N,M,K,PN,M,K,P ,每两个整数之间用一个空格隔开。

接下来 MM 行,每行三个整数 a_i,b_i,c_iai,bi,ci ,代表编号为 a_i,b_iai,bi 的点之间有一条权值为 c_ici 的有向边,每两个整数之间用一个空格隔开。

输出格式:

输出文件包含 TT 行,每行一个整数代表答案。

输入输出样例

输入样例#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

对于第一组数据,最短路为 3 1 – 5, 1 – 2 – 4 – 5, 1 – 2 – 3 – 5 3 条合法路径。

【测试数据与约定】

对于不同的测试点,我们约定各种参数的规模不会超过如下

测试点编号  

TT 

NN 

MM 

KK 

是否有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\le P \le 10^9,1 \le a_i,b_i \le N ,0 \le c_i \le 10001P109,1ai,biN,0ci1000 

数据保证:至少存在一条合法的路线。

 

算法分析:

首先用spfa求出最短路,d[i]表示i点到起点的最短距离Dis[i]功能就可以告诉我们当前所走的路是否有冤枉路了。解释:冤枉路是指从A点至B点所走的路径不是最短路,也就是说一共允许你走K冤枉路的长度,每走一次冤枉路都会消耗这个余额。Dp求解dp(i,j)就表示你当前在i点,还允许你走j容量的冤枉路

那无穷多条合法路线:首先肯定是在路径里出现了环。(解释:因为简单路线肯定是有限条,无穷的肯定是有环)题目里提到了0边,这就使我们进一步想到0——如果这个环不是零环,那肯定就不是在最短路上面了(何必绕着一点跑到黑呢!)肯定就会消耗冤枉路容量,就不可能是有限条。所以如果有0环出现,判断-1即可。

注意事项

虽然1号点一定能走到n号点,但是公园中有些点可能无法到达N,所以通过建立反向图的方式反向SPFA来排除那些无法到终点的点,把能到终点的点vis[i]值标为1即可,在dp的时候把vis值为0的点跳过即可

 

代码实现:

 

 

#include<bits/stdc++.h>
using namespace std;
const int INF=0x7ffffff;
struct node
{int x;int w;node(int x1,int w1):x(x1),w(w1){}
};
int n,m,k,p;
#define N 100007
vector<node>g1[N];
vector<node>g2[N];
int dis[N];
int ans[N][55];
bool vis[N],flag[N][55];
bool a[N];
int dfs(int a,int b)//a代表现在所在的点,b的容量
{if(b<0) {return 0;}else if(flag[a][b]==1){return -INF;}else if(ans[a][b]!=-1)return ans[a][b];else{flag[a][b]=1;int key=0;if(a==n){key++;}for(int i=0;i<g1[a].size();i++){int g=g1[a][i].x;int y=g1[a][i].w;int u=dis[g]-dis[a];if(vis[g]==0)//肯定到不了的终点{continue;}int w=dfs(g,b-(y-u));if(w==-INF){return -INF;}else{key=(key+w)%p;}}ans[a][b]=key%p;flag[a][b]=0;return key;}
}
int fspfa(int s)  //建立反向图,用vis记录终点是否可以到起点
{memset(vis,0,sizeof(vis));queue<int>q;q.push(s);vis[s]=1;while(!q.empty()){int i=q.front();q.pop();for(int j=0;j<g2[i].size();j++){int k=g2[i][j].x;if(!vis[k]){vis[k]=1;q.push(k);}}}
}
int spfa(int s)
{for(int i=2;i<=n;i++)dis[i]=INF;memset(vis,0,sizeof(vis));queue<int>q;q.push(s);dis[s]=0;vis[s]=1;while(!q.empty()){int i=q.front();q.pop();vis[i]=0;for(int j=0;j<g1[i].size();j++){int k=g1[i][j].x;int w=g1[i][j].w;if(dis[k]>dis[i]+w){dis[k]=dis[i]+w;if(!vis[k]){vis[k]=1;q.push(k);}}}}
}
int main()
{int T;scanf("%d",&T);while(T--){scanf("%d%d%d%d",&n,&m,&k,&p);for(int i=1;i<=n;i++){g1[i].clear();g2[i].clear();for(int j=0;j<=k;j++){ans[i][j]=-1;flag[i][j]=0;}}for(int i=1;i<=m;i++){int a,b,c;scanf("%d%d%d",&a,&b,&c);g1[a].push_back(node(b,c));g2[b].push_back(node(a,c));}spfa(1);fspfa(n);int z=dfs(1,k);if(z==-INF){printf("%d\n",-1);}else{printf("%d\n",z);}}return 0;
}

这篇关于spfa+dp+反向spfa 洛谷  P3953 逛公园的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/379967

相关文章

Linux如何做ssh反向代理

SSH反向代理是一种通过SSH协议实现的安全远程访问方式,它允许客户端通过SSH连接到一台具有公网IP的代理服务器,然后这台代理服务器再将请求转发给内部网络中的目标主机。以下是实现SSH反向代理的步骤: 一、准备工作 确保服务器配置: 内网服务器(目标主机)和外网服务器(代理服务器)都安装了SSH服务,并且能够通过SSH进行互相访问。内网服务器上的服务(如Web服务、数据库服务等)需要在本地

高精度计算(代码加解析,洛谷p1601,p1303)除法待更新

目录 高精度加法 高精度减法 高精度乘法 高精度加法 我们知道在c++语言中任何数据类型都有一定的表示范围。当两个被加数很大时,正常加法不能得到精确解。在小学,我们做加法都采用竖式方法。那么我们也只需要按照加法进位的方式就能得到最终解。 8 5 6+ 2 5 5-------1 1 1 1 加法进位: c[i] = a[i] + b[i];if(c[i] >=

洛谷 凸多边形划分

T282062 凸多边形的划分 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 先整一个半成品,高精度过两天复习一下补上 #include <iostream>#include <algorithm>#include <set>#include <cstring>#include <string>#include <vector>#include <map>

Nginx反向代理功能及动静分离实现

一:Nginx支持正向代理和反向代理 1.正向代理 正向代理,指的是通过代理服务器 代理浏览器/客户端去重定向请求访问到目标服务器 的一种代理服务。 正向代理服务的特点是代理服务器 代理的对象是浏览器/客户端,也就是对于目标服务器 来说浏览器/客户端是隐藏的。 正向代理是客户端指定让代理去访问哪个服务,代表客户端的利益。 2.反向代理 反向代理,指的是浏览器/客户端并不知道自己要

能量项链,洛谷

解释:  环形dp问题还是考虑将环拉直,可以参考我上一篇文章:环形石子合并 [2 3 5 10 2] 3 5 10 将环拉直,[]内是一个有效的区间,可以模拟吸收珠子的过程,         如[2 3 5] <=>(2,3)(3,5)    2是头,3是中间,5是尾 len >= 3:因为最后[2 10 2]是最小的可以合并的有效区间 len <= n + 1因为[2 3

GDB 反向调试

使用调试器时最常用的功能就是step, next, continue,这几个调试命令都是“往下执行”的, 但是很多时候会有这种需求:你在调试的过程中多跳过了几步而错过中间过程,这时候不得不重头调试一遍,非常麻烦。而GDB从7.0版本开始支持反向调试功能,也就是允许你倒退着运行程序,或者说撤销程序执行的步骤从而会到以前的状态。   直观地来看,加入你正在使用GDB7.0以上版本的调试器并且运行在

代理服务器介绍,正向代理(校园网,vpn,http隧道技术),反向代理(公司服务器,frp服务),NAT和代理服务器的相同/不同点

目录 代理服务器 介绍 类型  正向代理 引入 介绍  vpn http隧道技术 反向代理 引入 隧道技术 介绍 frp服务 NAT和代理服务器 相同点 不同点 NAT 代理服务器 代理服务器 介绍 一种中间服务器,充当客户端(如个人计算机或移动设备)与目标服务器(如网站服务器)之间的中介 它接受客户端的请求,然后将这些请求转发给目标服务器,再把

洛谷P5490扫描线

0是最小的数字,将一个线段看成一个区间,对于一个矩形,从下扫到上,入边为1,而出边为-1,意思是将这个区间上的所有点加1(区间修改).把线段表示为Line[i],其中记录了l,r,h,tag,左右端点,高度,入边还是出边(1或-1) 那么每次区间修改后不为0的区间它的值可能是1,2,3或者是其它数字,这不好统计,可以将它转化一下,0是不是表示没有被覆盖过的地方,我们只要统计0的个数然后用总长减去

[置顶]Nginx反向代理部署指南

一.反向代理   我们都知道,80端口是web服务的默认端口,其他主机访问web服务器也是默认和80端口进行web交互,而一台服务器也只有一个80端口,这是约定俗成的标准. 我们来看下面两个场景:  1.服务器的80端口被占用了,我们想实现服务器的其他端口(比如port:2368)web服务.  2.我们想在一台服务器上实现多个站点的web服务. 要解决这个问题,需要用到反向代理,下面的

挤牛奶洛谷uasco

题目描述 三个农民每天清晨5点起床,然后去牛棚给3头牛挤奶。第一个农民在300秒(从5点开始计时)给他的牛挤奶,一直到1000秒。第二个农民在700秒开始,在 1200秒结束。第三个农民在1500秒开始2100秒结束。期间最长的至少有一个农民在挤奶的连续时间为900秒(从300秒到1200秒),而最长的无人挤奶的连续时间(从挤奶开始一直到挤奶结束)为300秒(从1200秒到1500秒)。