题目: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. IT技术博客

    博客收藏大全: 陈皓博客: 陈硕的博客: 风云的博客: 当然我在扯淡: hellogirl: 田守枝Java技术博客: 廖雪峰博客: Milo游戏开发:

  2. 关于Spring Cloud Feign的一些记录!

    学习Spring Cloud Feign过程中,相关资料都会反复强调:微服务调用的话(@FeignClient)  客户端方法的返回值和服务端方法的返回值还有方法名之类的都是要求一致的! 关于方法名是 ...

  3. let和const的一些知识点

    let和const 不可以重复声明 不会发生变量提升,因此必须在声明之后使用,否则报错! 只在声明所在的块级作用域内有效 let 同一个作用域内不能重复声明同一个变量: function func() ...

  4. element-ui 使用笔记

    1,获取级联选择器 cascader的值 获取value值:就是v-model绑定的值, 获取label值:要先给cascader组件一个ref值,然后通过 this.$refs.组件的ref值.cu ...

  5. 此处有加速 apt-get github docker pull

    ubuntu get-apt 加速 创建 aptupdate.sh 脚本,内容为: #!/bin/bash mv /etc/apt/sources.list /etc/apt/sources.list ...

  6. Installing Node.js and Express on Ubuntu

    Installing Node.js and Express on Ubuntu 1. 在nodejs官网上下载Linux Binaries(已经包含了npm):2. 安装Node.js下载后解压,并 ...

  7. Maven实战02_Maven的安装和配置

    1:在Windows上安装Maven 本人系统环境:win10  + JDK1.8 + apache-maven-3.3.9 在安装Maven之前,首先要确定你的Java环境是否已经配置好了,你是否已 ...

  8. <init>与<clinit>的区别

    在编译生成class文件时,会自动产生两个方法,一个是类的初始化方法<clinit>, 另一个是实例的初始化方法<init> <clinit>:在jvm第一次加载c ...

  9. Linux User and Group Management

    linux is a multi-user and multitasking OS. In Linux, you can create any number of user account and g ...

  10. Django项目:CRM(客户关系管理系统)--23--15PerfectCRM实现King_admin多条件过滤

    登陆密码设置参考 http://www.cnblogs.com/ujq3/p/8553784.html list_filter = ('source','consultant','consult_co ...