洛谷P3953 逛公园(dp 拓扑排序)
题意
Sol
去年考NOIP的时候我好像连最短路计数都不会啊qwq。。
首先不难想到一个思路,\(f[i][j]\)表示到第\(i\)个节点,与最短路之差长度为\(j\)的路径的方案数
首先把每个节点的最短路求出来
转移的时候按拓扑序(也就是按距离从小到大排序)转移一下
然而有\(0\)边的时候会挂掉,原因是会有dis相同的时候,这时候单按dis排序会无法判断转移方向
一种方案是直接把所有\(0\)边加入到新图中,拓扑排序一遍。得到第二关键字
同时判断一下\(0\)环
#include<bits/stdc++.h>
#define Pair pair<int, int>
#define MP make_pair
#define fi first
#define se second
using namespace std;
const int MAXN = 100001, INF = 1e9 + 7;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int T, N, M, K, mod, f[MAXN][51], dis1[MAXN], disn[MAXN], vis[MAXN], inder[MAXN], id[MAXN];
vector<Pair> v[MAXN], rv[MAXN];
vector<pair<pair<int, int>, int> > P;
vector<int> E[MAXN];
void init() {
memset(f, 0, sizeof(f));
memset(inder, 0, sizeof(inder));
P.clear();
f[1][0] = 1;
N = read(); M = read(); K = read(); mod = read();
for(int i = 1; i <= N; i++) v[i].clear(), E[i].clear();
for(int i = 1; i <= M; i++) {
int x = read(), y = read(), z = read();
v[x].push_back(MP(y, z)); rv[y].push_back(MP(x, z));
if(!z) E[x].push_back(y), inder[y]++;
}
}
void add(int &x, int y) {
if(x + y < 0) x = (x + y + mod);
else x = (x + y >= mod ? x + y - mod : x + y);
}
int Topsort() {
int cnt = 0; queue<int> q;
for(int i = 1; i <= N; i++) if(!inder[i]) id[i] = ++cnt, q.push(i);
while(!q.empty()) {
int p = q.front(); q.pop();
for(int i = 0, to; i < E[p].size(); i++)
if(!(--inder[to = E[p][i]])) q.push(to), id[to] = ++cnt;
}
for(int i = 1; i <= N; i++) if(inder[i] && (dis1[i] + disn[i] <= dis1[N] + K)) return -1;
return 0;
}
void Dij(int bg, int *dis) {
priority_queue<Pair> q; q.push(MP(0, bg));
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= N; i++) dis[i] = INF + 1; dis[bg] = 0;
while(!q.empty()) {
if(vis[q.top().se]) {q.pop(); continue;}
int p = q.top().se; q.pop(); vis[p] = 1;
if(bg == 1) {
for(int i = 0, to; i < v[p].size(); i++)
if(dis[to = v[p][i].fi] > dis[p] + v[p][i].se)
dis[to] = dis[p] + v[p][i].se, q.push(MP(-dis[to], to));
} else {
for(int i = 0, to; i < rv[p].size(); i++)
if(dis[to = rv[p][i].fi] > dis[p] + rv[p][i].se)
dis[to] = dis[p] + rv[p][i].se, q.push(MP(-dis[to], to));
}
}
}
int solve() {
Dij(1, dis1);
Dij(N, disn);
if(Topsort() == -1) return -1;
for(int i = 1; i <= N; i++) P.push_back(MP(MP(dis1[i], id[i]), i));
sort(P.begin(), P.end());
f[1][0] = 1;
for(int j = 0; j <= K; j++) {
for(int i = 0; i < N; i++) {
int x = P[i].se;
for(int k = 0; k < v[x].size(); k++) {
int to = v[x][k].fi, w = v[x][k].se, ps = dis1[x] + j + w - dis1[to];
if(ps <= K) add(f[to][ps], f[x][j]);
}
}
}
int ans = 0;
for(int i = 0; i <= K; i++) add(ans, f[N][i]);
return ans;
}
int main() {
T = read();
while(T--) {
init();
printf("%d\n", solve());
}
return 0;
}
/*
*/
洛谷P3953 逛公园(dp 拓扑排序)的更多相关文章
- 洛谷P3953 逛公园(NOIP2017)(最短/长路,拓扑排序,动态规划)
洛谷题目传送门 又是一年联赛季.NOIP2017至此收官了. 这个其实是比较套路的图论DP了,但是细节有点恶心. 先求出\(1\)到所有点的最短路\(d1\),和所有点到\(n\)的最短路\(dn\) ...
- 洛谷P3953 逛公园
DP+图论大毒瘤. 推荐这个博客. 先跑两遍最短路,搞掉一些无用点. 然后选出最短路上的边,做拓扑排序. 然后每层DP. 具体看代码. 用到的数组较多,记得清空. #include <cstdi ...
- 洛谷P3953 逛公园 [noip2017] 图论+dp
正解:图论(最短路)+dp(记忆化搜索) 解题报告: 这题真的是个好东西! 做了这题我才发现我的dij一直是错的...但是我以前用dij做的题居然都A了?什么玄学事件啊...我哭了TT 不过其实感觉还 ...
- 2018.11.01 洛谷P3953 逛公园(最短路+dp)
传送门 设f[i][j]f[i][j]f[i][j]表示跟最短路差值为iii当前在点jjj的方案数. in[i][j]in[i][j]in[i][j]表示在被选择的集合当中. 大力记忆化搜索就行了. ...
- 洛谷P3953逛公园
题目 作为\(NOIp2017D1T3\) 这个题还是很良心的,至少相对于\(NOIp2018\)来说,希望\(NOIp2019\)不会这么坑吧. 这个题可以作为记忆化搜索的进阶题了,做这个题的方法也 ...
- 洛谷 P3953 逛公园
题目链接 思路 首先没有0边,且k为0的情况就是最短路计数. 如果k不为0,看到k<=50,想到dp. 设f[u][i]表示到达u点比最短路多走i的路径数,转移到v点. f[u][i]+=f[v ...
- 洛谷 P3953 逛公园【spfa+记忆化dfs+bfs】
spfa预处理出最短路数组dis,然后反向建边bfs出ok[u]表示u能到n点 然后发现有0环的话时候有inf解的,先dfs找0环判断即可 然后dfs,设状态f[u][v]为到u点,还可以跑最短路+v ...
- 洛谷 P1053 逛公园 解题报告
P3953 逛公园 问题描述 策策同学特别喜欢逛公园. 公园可以看成一张\(N\)个点\(M\)条边构成的有向图,且没有自环和重边.其中1号点是公园的入口,\(N\)号点是公园的出口,每条边有一个非负 ...
- P3953 逛公园(dp,最短路)
P3953 逛公园 题目描述 策策同学特别喜欢逛公园.公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经 ...
随机推荐
- Flink学习笔记:Operators之CoGroup及Join操作
本文为<Flink大数据项目实战>学习笔记,想通过视频系统学习Flink这个最火爆的大数据计算框架的同学,推荐学习课程: Flink大数据项目实战:http://t.cn/EJtKhaz ...
- docker搭建elk+cerebro环境
ELK的帮助手册 Docker Hub官网:https://hub.docker.com/r/sebp/elk/ Docker ELK使用文档:http://elk-docker.readthedoc ...
- 安装mysqlclient, 链接mysql失败,提示“Library not loaded: @rpath/libmysqlclient.21.dylib”
问题: >>> import MySQLdb Traceback (most recent call last): File "<stdin>", l ...
- Python中的range和xrange区别
range 函数说明:range([start,] stop[, step]),根据start与stop指定的范围以及step设定的步长,生成一个序列. range示例: >>> r ...
- 文献综述十七:基于 sql环境下超市管理系统的设计与实现
一.基本信息 标题:基于 sql环境下超市管理系统的设计与实现 时间:2018 出版源:智能计算机与应用 文件分类:uml技术的研究 二.研究背景 从超市管理系统的实际应用出发,在系统分析过程中,从功 ...
- 爬虫--XPATH解析
今天说一下关于爬取数据解析的方式---->XPATH,XPATH是解析方式中最重要的一种方式 1.安装:pip install lxml 2.原理 1. 获取页面源码数据 2.实例化一个etr ...
- 使用discover批量执行用例
TestLaoder 该类负责根据各种条件加载测试用例,并将它们返回给测试套件,正常情况下,不需要创建这个类的实例,unittest提供了可以共享的defaultTestLoader类,可以使用其子类 ...
- TortoiseGit学习系列之TortoiseGit是什么?
写该文章目的 肯定有人会遇到这样的问题: 最近换了一份新工作,新公司的源码管理都是使用GIT,习惯了之前的TFS和SVN进行项目源码管理和团队开发,第一次使用GIT进行团队开发和源码管理,颇有一些不习 ...
- unity鼠标拖动物体旋转
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> / ...
- Java的IO流各个类的使用原则
参考:http://blog.csdn.net/ilibaba/article/details/3955799 Java IO 的一般使用原则(花多眼乱,其实每个类都有专门的作用): 这里有详细介绍: ...