题目: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环的更多相关文章

  1. NOIP 2017 逛公园 记忆化搜索 最短路 好题

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

  2. 洛谷P1434滑雪题解及记忆化搜索的基本步骤

    题目 滑雪是一道dp及记忆化搜索的经典题目. 所谓记忆化搜索便是在搜索的过程中边记录边搜索的一个算法. 当下次搜到这里时,便直接使用. 而且记忆化搜索一定要满足无后效性,为什么呢,因为如果不满足无后效 ...

  3. 洛谷P1192 台阶问题【记忆化搜索】

    题目:https://www.luogu.org/problemnew/show/P1192 题意: 给定n和k,一个人一次可以迈1~k步,问走n步有多少种方案. 思路: 本来傻乎乎上来就递归,显然会 ...

  4. 洛谷P1040 加分二叉树【记忆化搜索】

    题目链接:https://www.luogu.org/problemnew/show/P1040 题意: 某一个二叉树的中序遍历是1~n,每个节点有一个分数(正整数). 二叉树的分数是左子树分数乘右子 ...

  5. 洛谷P3953 [NOIP2017]逛公园

    K<=50,感觉可以DP 先建反图求出从n到各个点的最短路,然后在正图上DP 设f[当前点][比最短路多走的距离]=方案数 转移显然是 $f[v][res]=\sum f[u][res+tmp] ...

  6. 洛谷 P1141【BFS】+记忆化搜索+染色

    题目链接:https://www.luogu.org/problemnew/show/P1141 题目描述 有一个仅由数字 0 与 1 组成的n×n 格迷宫.若你位于一格0上,那么你可以移动到相邻 4 ...

  7. 洛谷P3906 Hoof Paper, Scissor (记忆化搜索)

    这道题问的是石头剪刀布的的出题问题 首先不难看出这是个dp题 其次这道题的状态也很好确定,之前输赢与之后无关,确定三个状态:当前位置,当前手势,当前剩余次数,所以对于剪刀,要么出石头+1分用一次机会, ...

  8. 【洛谷1434 [SHOI2002]滑雪】记忆化搜索

    AC代码 #include <bits/stdc++.h> using namespace std; #define ms(a,b) memset(a,b,sizeof(a)) typed ...

  9. 【题解】洛谷P3953 [NOIP2017TG] 逛公园(记忆化搜索+SPFA)

    题目来源:洛谷P3953 思路 先用SPFA求一遍最短路 在求最短路的同时可以把所有点到终点的最短路求出来 dis数组 注意要反向SPFA  因为从起点开始可能会走到一些奇怪的路上导致时间负责度增加 ...

随机推荐

  1. Java笔记 - 线程与并行API

    一.线程简介 1.线程与进程 每个进程都具有独立的代码和数据空间,进程间的切换会有较大的开销.线程是轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开 ...

  2. 模板——AC自动机

    传送门:QAQQAQ 定义nxt[u]=v表示从u开始不断沿着失配边跳到的第一个是标记点的端点v,那么我们再匹配时沿着last跳,每跳到一个last,它就一定对应一个模式串,所以效率是非常高的. 和K ...

  3. String类的trim() 方法

    用于删除字符串的头尾空白符. 语法:public String trim() 返回值:删除头尾空白符的字符串. public class Test {    public static void ma ...

  4. [原创]关于时间格式的坑(kk:mm:ss、HH:mm:ss与hh:mm:ss)

    笔者在项目中使用 kk:mm:ss表示24小时制,却发现与所想的不同,特记此坑,提醒众人: kk:mm:ss   24小时制,时间为1:00:00-24:59:59 HH:mm:ss 24小时制,时间 ...

  5. Anaconda如何配置多版本Python

    https://blog.csdn.net/guanmaoning/article/details/80031279

  6. Oracle的UTL_FILE.FOPEN学习笔记

    Oracle提供的文件操作包UTL_FILE包中的UTL_FILE.FOPEN负责打开一个文件. UTL_FILE.FOPEN(location in varchar2, filename in va ...

  7. ERP或PLM系统-物料编码管理的技术实现

    1 企业现状 企业日常经营过程中会产生大量的文档,如设计图纸.变更单.计算书.设计方案等,如果是制造企业还会产生大量的产品.组成产品的零部件等物料,这些数据在进入信息系统前都需要有一个唯一的标识,也就 ...

  8. [转]一分钟明白 VS manifest 原理

    什么是vs 程序的manifest文件 manifest 是VS程序用来标明所依赖的side-by-side组建,如ATL, CRT等的清单. 为什么要有manifest文件 一台pc上,用一组建往往 ...

  9. html常用标签详解3-a标签

    a标签 1.a标签的属性 a标签属于行内元素标签,双标签<a></a> href:a标签的跳转地址 target:打开方式(_self自身:_blank:新窗口) title: ...

  10. JavaSE_05_反射

    1.什么是反射? Java反射说的是在运行状态中,对于任何一个类,我们都能够知道这个类有哪些方法和属性.对于任何一个对象,我们都能够对它的方法和属性进行调用.我们把这种动态获取对象信息和调用对象方法的 ...