题目分析:

首先考虑无数条的情况。出现这种情况一定是一条合法路径经过了$ 0 $环中的点。那么预先判出$ 0 $环中的点和其与$ 1 $和$ n $的距离。加起来若离最短路径不超过$ k $则输出$ -1 $,否则这些点必定不被经过,接着dp后效性消失。由于每条边转移了$ k $次它的起点到终点的状态,所以总时间复杂度为$ O(n+mk) $,可以通过所有数据。

代码:

 #include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
using namespace std; typedef pair<int,int> pr; const int maxn = ; int n,m,k,p;
vector<pair<int,int> > g[maxn],rg[maxn];
vector <int> ng[maxn]; int dfn[maxn],low[maxn],instack[maxn],scc[maxn],cl;
int f[maxn][],arr[maxn][];
stack <int> sta; void init(){
memset(dfn,,sizeof(dfn));
memset(arr,,sizeof(arr));
memset(low,,sizeof(low));
memset(instack,,sizeof(instack));
memset(scc,,sizeof(scc));
memset(f,,sizeof(f));
cl = ;
} void tarjan(int now){
low[now] = dfn[now] = ++cl;
sta.push(now);
for(int i=;i<ng[now].size();i++){
int k = ng[now][i]; if(instack[k]) continue;
if(dfn[k]) { low[now] = min(low[now],dfn[k]); }
else{ tarjan(k); low[now] = min(low[now],low[k]); }
}
if(low[now] == dfn[now]){
stack<int> tpp;int num = ;
while(true){
int tp = sta.top();sta.pop();tpp.push(tp);num++;
instack[tp] = ; scc[tp]=;
if(now == tp) break;
}
if(num == ) scc[tpp.top()] = ;
}
} void read(){
scanf("%d%d%d%d",&n,&m,&k,&p);
for(int i=;i<=n;i++) g[i].clear();
for(int j=;j<=n;j++) ng[j].clear();
for(int j=;j<=n;j++) rg[j].clear();
for(int i=;i<=m;i++){
int u,v,w; scanf("%d%d%d",&u,&v,&w);
g[u].push_back(make_pair(v,w));
rg[v].push_back(make_pair(u,w));
if(w == ) ng[u].push_back(v);
}
} int res;
int d[maxn][];
priority_queue<pr,vector<pr>,greater<pr> > pq;
void solve_dist(){
memset(d,0x3f,sizeof(d));
pq.push(make_pair(,));
while(!pq.empty()){
pair<int,int> tp = pq.top();pq.pop();
if(d[tp.second][] > 1e9) d[tp.second][] = tp.first;
else continue;
for(int j=;j<g[tp.second].size();j++){
int nxt = g[tp.second][j].first,data = g[tp.second][j].second;
data += d[tp.second][];
if(data > d[nxt][]) continue;
pq.push(make_pair(data,nxt));
}
}
res = d[n][];
pq.push(make_pair(,n));
while(!pq.empty()){
pair<int,int> tp = pq.top();pq.pop();
if(d[tp.second][] > 1e9) d[tp.second][] = tp.first;
else continue;
for(int j=;j<rg[tp.second].size();j++){
int nxt = rg[tp.second][j].first,data = rg[tp.second][j].second;
data += d[tp.second][];
if(data > d[nxt][]) continue;
pq.push(make_pair(data,nxt));
}
}
} void dfs(int now,int lw){
if(arr[now][lw]) return;
int nowd = d[now][]+lw;arr[now][lw] = ;
for(int j=;j<rg[now].size();j++){
int nxt = rg[now][j].first,data = rg[now][j].second;
if(scc[nxt])continue;
int nd = nowd-data; nd -= d[nxt][];
if(nd < ) continue;
if(nd > k) continue;
dfs(nxt,nd);
f[now][lw] += f[nxt][nd]; f[now][lw] %= p;
}
} void work(){
for(int i=;i<=n;i++) if(!dfn[i]) tarjan(i);
if(scc[]||scc[n]) {puts("-1");return;} solve_dist(); for(int i=;i<=n;i++)
if(scc[i]) if(d[i][]+d[i][]<=res+k){puts("-1");return;} f[][] = ;arr[][] = ;int ans = ;
for(int i=;i<=k;i++) {
dfs(n,i);ans += f[n][i]; ans %= p;
}
printf("%d\n",ans);
} int main(){
int t; scanf("%d",&t);
while(t--){ init(); read(); work(); }
return ;
}

[NOIP2017] 逛公园 【最短路】【强连通分量】的更多相关文章

  1. [NOIP2017]逛公园 最短路+拓扑排序+dp

    题目描述 给出一张 $n$ 个点 $m$ 条边的有向图,边权为非负整数.求满足路径长度小于等于 $1$ 到 $n$ 最短路 $+k$ 的 $1$ 到 $n$ 的路径条数模 $p$ ,如果有无数条则输出 ...

  2. [NOIP2017]逛公园 最短路图 拓扑序DP

    ---题面--- 题解: 挺好的一道题. 首先我们将所有边反向,跑出n到每个点的最短路,然后f[i][j]表示从i号节点出发,路径长比最短路大j的方案数. 观察到,如果图中出现了0环,那么我们可以通过 ...

  3. [NOIP2017] 逛公园 (最短路,动态规划&记忆化搜索)

    题目链接 Solution 我只会60分暴力... 正解是 DP. 状态定义: \(f[i][j]\) 代表 \(1\) 到 \(i\) 比最短路长 \(j\) 的方案数. 那么很显然最后答案也就是 ...

  4. [NOIP2017] 逛公园

    [NOIP2017] 逛公园 题目大意: 给定一张图,询问长度 不超过1到n的最短路长度加k 的1到n的路径 有多少条. 数据范围: 点数\(n \le 10^5\) ,边数\(m \le 2*10^ ...

  5. 【比赛】NOIP2017 逛公园

    考试的时候灵光一闪,瞬间推出DP方程,但是不知道怎么判-1,然后?然后就炸了. 后来发现,我只要把拓扑和DP分开,中间加一个判断,就AC了,可惜. 看这道题,我们首先来想有哪些情况是-1:只要有零环在 ...

  6. 【题解】NOIP2017逛公园(DP)

    [题解]NOIP2017逛公园(DP) 第一次交挂了27分...我是不是必将惨败了... 考虑这样一种做法,设\(d_i\)表示从该节点到n​节点的最短路径,\(dp(i,k)\)表示从\(i\)节点 ...

  7. NOIP2017逛公园(dp+最短路)

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

  8. NOIP2017 逛公园 题解报告 【最短路 + 拓扑序 + dp】

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

  9. Luogu P3953 逛公园(最短路+记忆化搜索)

    P3953 逛公园 题面 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有自环和重边.其中 \(1\) 号点是公园的入口,\(N\) 号点是公 ...

  10. [NOIP2017]逛公园 题解

    我连D1T3都不会我联赛完蛋了 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 N 个点 M 条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口, N 号点是公园的出口,每条边有一个非负 ...

随机推荐

  1. MySQL root密码忘记,原来还有更优雅的解法!

    一直以来,对于MySQL root密码的忘记,以为只有一种解法-skip-grant-tables. 问了下群里的大咖,第一反应也是skip-grant-tables.通过搜索引擎简单搜索了下,无论是 ...

  2. ASP.NET Core依赖注入——依赖注入最佳实践

    在这篇文章中,我们将深入研究.NET Core和ASP.NET Core MVC中的依赖注入,将介绍几乎所有可能的选项,依赖注入是ASP.Net Core的核心,我将分享在ASP.Net Core应用 ...

  3. Win10 Anaconda下TensorFlow-GPU环境搭建详细教程(包含CUDA+cuDNN安装过程)

    目录 前言 第一步:安装Anaconda 1.下载和安装 2.配置Anaconda环境变量 第二步:安装TensorFlow-GPU 1.创建conda环境 2.激活环境 3.安装tensorflow ...

  4. C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - 树形选择项目的标准例子

    用成套的现成的方法引导大家开发程序,整个团队的开发效率会很高.例如我们现在有30多个开发人员,若有300个开发人员,这开发工作很容易乱套,我们需要有效的管理维护所有团队的开发工作.把数据结构.通用的组 ...

  5. 什么是车辆识别代码(VIN)

    车辆识别代码(VIN),VIN是英文Vehicle Identification Number(车辆识别码)的缩写.因为ASE标准规定:VIN码由17位字符组成,所以俗称十七位码.正确解读VIN码,对 ...

  6. MySQL 使用左连接替换not in

    众所周知,左连接和右连接的含义是以哪一张表为准. 左连接就是以左表为准,查出的结果中包含左表所有的记录,如果右表中没有与其对应的记录,那么那一行记录中B表部分的内容就全是NULL. 现在有两个表,一个 ...

  7. css行内省略号、垂直居中

    应用场景分析: 一.当你的文字限定行数,超出部分的文字用省略号显示. (有两个使用场景:1.单行 2.多行) // 单行 overflow: hidden; text-overflow:ellipsi ...

  8. IntelliJ IDEA使用教程(非常全面)

    这个编辑器我就不再多做介绍了.直接开始新建maven hello world 的Java web项目啦 你电脑上得有jdk1.7,或者1.8,然后就是maven3.x吧,再有就是tomcat7以上吧. ...

  9. java从request中获取GET和POST请求参数

    URL和参数列表 一 获取请求方式 request.getMethod(); get和post都可用, 二 获取请求类型 request.getContentType(); get和post都可用,示 ...

  10. linux下使用sha256sum生成sha256校验文件,并校验其一致性

    [root@localhost ]# " >test.zip 生成sha256文件校验文件 [root@localhost ]# sha256sum test.zip >test ...