洛谷3953 (NOIp2017) 逛公园——记忆化搜索+用栈判0环
题目:https://www.luogu.org/problemnew/show/P3953
因为K只有50,所以想到用dp[ cr ][ j ]表示在点cr、比最短路多走了 j 的方案数。(看了TJ才知道)
因为不是DAG,所以没有拓扑序,就用记忆化搜索就好了。
判0环可以用bool数组,而且是栈的样子,表示从自己出发又一模一样地走回来就说明有0环。
0环还要在一条合法路径上才行。判断是dis[cr]+k+dit[cr]<=dis[n]+K。(dit是从n到各点的最短路)还可以用它剪枝。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
const int N=1e5+,M=2e5+,S=,INF=0x3f3f3f3f;
int T,n,m,K,mod,hd[N],thd[N],xnt,tnt,dis[N],dit[N],f[N][S],ans;
bool vis[N],flag,gx[N][S];
struct Ed{
int nxt,to,w;
Ed(int n=,int t=,int w=):nxt(n),to(t),w(w) {}
}ed[M],ted[M];
int rdn()
{
int ret=;char ch=getchar();
while(ch>''||ch<'')ch=getchar();
while(ch>=''&&ch<='')(ret*=)+=ch-'',ch=getchar();
return ret;
}
priority_queue<pair<int,int> >q;
void dj()
{
memset(dis,0x3f,sizeof dis);dis[]=;
memset(vis,,sizeof vis);
q.push(make_pair(-dis[],));
while(q.size())
{
int k=q.top().second;q.pop();
while(q.size()&&vis[k])k=q.top().second,q.pop();
if(vis[k])break;vis[k]=;
for(int i=hd[k],v;i;i=ed[i].nxt)
if(dis[v=ed[i].to]>dis[k]+ed[i].w)
dis[v]=dis[k]+ed[i].w,q.push(make_pair(-dis[v],v));
}
memset(dit,0x3f,sizeof dit);dit[n]=;
memset(vis,,sizeof vis);
q.push(make_pair(-dit[n],n));
while(q.size())
{
int k=q.top().second;q.pop();
while(q.size()&&vis[k])k=q.top().second,q.pop();
if(vis[k])break;vis[k]=;
for(int i=thd[k],v;i;i=ted[i].nxt)
if(dit[v=ted[i].to]>dit[k]+ted[i].w)
dit[v]=dit[k]+ted[i].w,q.push(make_pair(-dit[v],v));
}
}
int dfs(int cr,int k)
{
if(gx[cr][k]){flag=;return -;}
if(f[cr][k])return f[cr][k];
if(cr==n)f[cr][k]=;//别return f[cr]=1,万一在终点连了一个0环
gx[cr][k]=;
for(int i=hd[cr],v;i;i=ed[i].nxt)
{
int w=dis[cr]+k+ed[i].w-dis[v=ed[i].to];
if(w>K||(ll)dis[v]+w+dit[v]>dis[n]+K)continue;
(f[cr][k]+=dfs(v,w))%=mod;
if(flag)return -;
}
gx[cr][k]=;//!
return f[cr][k];
}
int main()
{
T=rdn();
while(T--)
{
memset(hd,,sizeof hd);xnt=;
memset(thd,,sizeof thd);tnt=;
n=rdn();m=rdn();K=rdn();mod=rdn();
int x,y,z;
for(int i=;i<=m;i++)
{
x=rdn();y=rdn();z=rdn();
ed[++xnt]=Ed(hd[x],y,z);hd[x]=xnt;
ted[++tnt]=Ed(thd[y],x,z);thd[y]=tnt;
}
dj();
memset(f,,sizeof f);memset(gx,,sizeof gx);
flag=;ans=dfs(,);
if(flag)ans=-;
printf("%d\n",ans);
}
return ;
}
洛谷3953 (NOIp2017) 逛公园——记忆化搜索+用栈判0环的更多相关文章
- NOIP 2017 逛公园 记忆化搜索 最短路 好题
题目描述: 策策同学特别喜欢逛公园.公园可以看成一张N个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. ...
- 洛谷P1434滑雪题解及记忆化搜索的基本步骤
题目 滑雪是一道dp及记忆化搜索的经典题目. 所谓记忆化搜索便是在搜索的过程中边记录边搜索的一个算法. 当下次搜到这里时,便直接使用. 而且记忆化搜索一定要满足无后效性,为什么呢,因为如果不满足无后效 ...
- 洛谷P1192 台阶问题【记忆化搜索】
题目:https://www.luogu.org/problemnew/show/P1192 题意: 给定n和k,一个人一次可以迈1~k步,问走n步有多少种方案. 思路: 本来傻乎乎上来就递归,显然会 ...
- 洛谷P1040 加分二叉树【记忆化搜索】
题目链接:https://www.luogu.org/problemnew/show/P1040 题意: 某一个二叉树的中序遍历是1~n,每个节点有一个分数(正整数). 二叉树的分数是左子树分数乘右子 ...
- 洛谷P3953 [NOIP2017]逛公园
K<=50,感觉可以DP 先建反图求出从n到各个点的最短路,然后在正图上DP 设f[当前点][比最短路多走的距离]=方案数 转移显然是 $f[v][res]=\sum f[u][res+tmp] ...
- 洛谷 P1141【BFS】+记忆化搜索+染色
题目链接:https://www.luogu.org/problemnew/show/P1141 题目描述 有一个仅由数字 0 与 1 组成的n×n 格迷宫.若你位于一格0上,那么你可以移动到相邻 4 ...
- 洛谷P3906 Hoof Paper, Scissor (记忆化搜索)
这道题问的是石头剪刀布的的出题问题 首先不难看出这是个dp题 其次这道题的状态也很好确定,之前输赢与之后无关,确定三个状态:当前位置,当前手势,当前剩余次数,所以对于剪刀,要么出石头+1分用一次机会, ...
- 【洛谷1434 [SHOI2002]滑雪】记忆化搜索
AC代码 #include <bits/stdc++.h> using namespace std; #define ms(a,b) memset(a,b,sizeof(a)) typed ...
- 【题解】洛谷P3953 [NOIP2017TG] 逛公园(记忆化搜索+SPFA)
题目来源:洛谷P3953 思路 先用SPFA求一遍最短路 在求最短路的同时可以把所有点到终点的最短路求出来 dis数组 注意要反向SPFA 因为从起点开始可能会走到一些奇怪的路上导致时间负责度增加 ...
随机推荐
- 用JS把数组内的日期转换为星期
核心代码 给定日期是星期几,应把字符串转为Date: new.Date('2017-12-30').getDay(); // 返回0,表示星期天,1:星期一…… 案例: 需求: 调用此方法 funct ...
- js时间比较大小,时间加减
第一种: //时间类比较 startTime= new Date(Date.parse(starttime)); endTime=new Date(Date.parse(endTime)); //进行 ...
- conda、pip换源以及conda、pip命令比较
conda换源: conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda ...
- JS中对象转数组方法总结
1.Array.from() 方法,用于数组的浅拷贝.就是将一个类数组对象或者可遍历对象转换成一个真正的数组.eg: let obj = { 0: 'nihao', 1: 'haha', 2: 'ga ...
- jeecms系统_自定义对象流程
库内新增对象Products 的流程说明: 第一步: com.jeecms.cms.entity.assist.base下建立模型基础类,BaseCmsProducts.java com.jeecms ...
- ERROR:ORA-30076: 对析出来源无效的析出字段
DEBUG:key: sql: select count(*) as col_0_0_ from jc_user cmsuser0_ where 1=1 and cmsuser0_.register_ ...
- AppbarLayout的简单用法
在许多App中看到, toolbar有收缩和扩展的效果, 例如: appbar.gif 要实现这样的效果, 需要用到: CoordinatorLayout和AppbarLayout的配合, 以及实 ...
- (一)SpringBoot入门【基于2.x版本】
SpringBoot入门[基于2.x版本] 一.SpringBoot简介 首先大家学习SpringBoot的话,我希望大家是有一定java基础的,如果是有Spring的基础的话,上手会更加得心应手,因 ...
- 在Linux下使用gcc运行C语言程序
Linux下使用最广泛的C/C++编译器是GCC,大多数的Linux发行版本都默认安装,不管是开发人员还是初学者,一般都将GCC作为Linux下首选的编译工具.本教程毫不犹豫地使用GCC来编译C程序. ...
- Leetcode459.Repeated Substring Pattern重复的子字符串
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成.给定的字符串只含有小写英文字母,并且长度不超过10000. 示例 1: 输入: "abab" 输出: True 解释 ...