题目描述:

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

策策每天都会去逛公园,他总是从1号点进去,从N号点出来。

策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到N号点的最短路长为d,那么策策只会喜欢长度不超过d + K的路线。

策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?

为避免输出过大,答案对P取模。

如果有无穷多条合法的路线,请输出-1。

题解:

话说去年提高组的难度真心大.......

我们一层一层考虑这道题:

1.首先,我们发现 $k<=50$,这个规模是非常小的。

2.由发现一,我们不难列出 dp 状态:$dp[i][j]$ 代表第 $i$ 号点到终点的距离比最短路大 $j$ 的方案数。

对于2的实现,我们考虑将每条边反着连

从N 点开始跑一遍到 1 号点的最短路,求出每个点到 N 号点的最短路。

我们这么做的原因是由于正着做可能会碰到不合法的状态,而逆推则不会碰到非法状态。

因为显然,1 号点的最短路径一定是全局的最短路径,于是可以由 1 号点转移的状态就全部是合法的,依此类推。

考虑正着进行记忆化搜索,从一个点转移到另一个点时,所需要走的最短路径为 $d[v]+w$。

而原本的最短路径为 $d[u]$,那么这就比 $d[u]$ 多了 $d[v]+w-d[u]$ 的路程。

假设当前的偏移量(即比最短路多出的量)为 $k$。

那么转移到 $v$ 点之后的偏移量就会变成 $k-(d[v]+w-d[u])$

我们这么进行记忆化搜索即可。

不过我们还要判一下 0 环。 开一个 $vis[i][k]$ 数组即可。

发现该状态再一次被访问且 $vis[i][k]=true$ 就说明出现 0 环,直接输出 -1.

Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<string>
using namespace std;
const int maxn=400000+4;
int d[maxn],s, n ,m, mod,tot;
struct SPFA{
int head[maxn],to[maxn],nex[maxn],val[maxn],cnt;
void addedge(int u,int v,int c){
nex[++cnt]=head[u],head[u]=cnt,to[cnt]=v,val[cnt]=c;
}
queue<int>Q;
bool inq[maxn];
void init(){
memset(head,0,sizeof(head)), memset(to,0,sizeof(to)), memset(nex,0,sizeof(nex)), memset(val,0,sizeof(val));
cnt=0;
}
void spfa(){
memset(d,0x3f,sizeof(d));
memset(inq,false,sizeof(inq));
d[s]=0,inq[s]=true; Q.push(s);
while(!Q.empty()){
int u=Q.front();Q.pop(); inq[u]=false;
for(int v=head[u];v;v=nex[v]){
if(d[u]+val[v]<d[to[v]]){
d[to[v]]=d[u]+val[v];
if(!inq[to[v]]){ Q.push(to[v]); inq[to[v]]=true; }
}
}
}
}
}T;
int head[maxn], to[maxn], nex[maxn], val[maxn], cnt;
void addedge(int u,int v,int c){
nex[++cnt]=head[u], head[u]=cnt, to[cnt]=v, val[cnt]=c;
}
int dp[100007][60];
bool vis[100007][60];
int dfs(int u,int k){
if(vis[u][k]) return -1;
if(dp[u][k]!=-1) return dp[u][k];
vis[u][k]=1;
int sum=0;
for(int v=head[u];v;v=nex[v]){
int tmp=k-(d[to[v]]+val[v]-d[u]);
if(tmp<0||tmp>tot) continue;
int delta=dfs(to[v], tmp);
if(delta==-1) return -1;
sum=(sum+delta)%mod;
}
if(k==0&&u==n) sum+=1;
vis[u][k]=0;
dp[u][k]=sum;
return sum;
}
int work(){
memset(dp,-1,sizeof(dp));
memset(head,0,sizeof(head));
memset(to,0,sizeof(to));
memset(val,0,sizeof(val));
cnt=0;
T.init();
scanf("%d%d%d%d",&n,&m,&tot,&mod);
for(int i=1;i<=m;++i){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
T.addedge(b,a,c); // 返向
addedge(a,b,c); // 正向
}
s=n;
T.spfa();
int ans=0;
for(int i=0;i<=tot;++i){
memset(vis,0,sizeof(vis));
int aa=dfs(1,i);
if(aa==-1) return -1;
ans=(ans+aa)%mod;
}
return ans;
}
int main(){
int T;
scanf("%d",&T);
while(T--) printf("%d\n",work());
return 0;
}

  

NOIP 2017 逛公园 记忆化搜索 最短路 好题的更多相关文章

  1. 洛谷3953 (NOIp2017) 逛公园——记忆化搜索+用栈判0环

    题目:https://www.luogu.org/problemnew/show/P3953 因为K只有50,所以想到用dp[ cr ][ j ]表示在点cr.比最短路多走了 j 的方案数.(看了TJ ...

  2. 2017广东工业大学程序设计竞赛决赛 题解&源码(A,数学解方程,B,贪心博弈,C,递归,D,水,E,贪心,面试题,F,贪心,枚举,LCA,G,dp,记忆化搜索,H,思维题)

    心得: 这比赛真的是不要不要的,pending了一下午,也不知道对错,直接做过去就是了,也没有管太多! Problem A: 两只老虎 Description 来,我们先来放松下,听听儿歌,一起“唱” ...

  3. NOIP 2017 逛公园 - 动态规划 - 最短路

    题目传送门 传送门 题目大意 给定一个$n$个点$m$条边的带权有向图,问从$1$到$n$的距离不超过最短路长度$K$的路径数. 跑一遍最短路. 一个点拆$K + 1$个点,变成一个DAG上路径计数问 ...

  4. NOIP 2017 逛公园 题解

    题面 这道题是一道不错的计数类DP: 首先我们一定要跑一遍dijkstra来求得每个点到1号点的最短路: 注意题干,题中并没有说所有点都可以到达n好点,只说了存在一条1号点到n号点的路径:所以我们在反 ...

  5. hduoj----1142A Walk Through the Forest(记忆化搜索+最短路)

    A Walk Through the Forest Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Jav ...

  6. HDU 1142 A Walk Through the Forest (记忆化搜索 最短路)

    A Walk Through the Forest Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Jav ...

  7. BZOJ-3208|记忆化搜索-花神的秒题计划Ⅰ

    背景[backboard]: Memphis等一群蒟蒻出题中,花神凑过来秒题-- 描述[discribe]: 花花山峰峦起伏,峰顶常年被雪,Memphis打算帮花花山风景区的人员开发一个滑雪项目. 我 ...

  8. [NOIp 2017]逛公园

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

  9. 洛谷 P3953 [ NOIP 2017 ] 逛公园 —— 最短路DP

    题目:https://www.luogu.org/problemnew/show/P3953 主要是看题解...还是觉得好难想啊... dfs DP,剩余容量的损耗是边权减去两点最短路差值...表示对 ...

随机推荐

  1. (六)api网关服务 zuul-过滤器

    开启上文服务: Zuul给我们的第一印象通常是这样:它包含了对请求的路由和过滤两个功能,其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础.过滤器功能则负责对请求的处理过 ...

  2. Calender

    public static void main(String[] args) { // TODO 自动生成的方法存根 Calendar c = new GregorianCalendar(); c., ...

  3. ie浏览器检测不到cookie的问题

    之前做项目由于客户的要求设置缓存必须由后台来设置必须使用cookie(session是没问题的),后期设置时出现了登录页面与首页来还跳转的局面.原因就是首页没检测到登录后的缓存,而后台验证到确实已经是 ...

  4. CSS中元素各种居中方法(思维导图)

    前言 用思维导图的方式简单总结一下各种元素的居中方法,如下图: 补充一下: table自带功能 100% 高度的 afrer before 加上 inline block优化 div 装成 table ...

  5. PHP正则表达式函数总结

    /* 测试环境:PHP5.3.29(PCRE8.32) */ 常用函数:(正则表达式规则基本同JS_RE_Read.txt) PS:1.PHP中的PCRE一般仅使用这三个修饰符:"i&quo ...

  6. JWT的初步了解以及session、cookie机制

    1.什么是状态保持? 想要了解JWT,首先需要知道什么是状态保持,举一个例子来说:无论是在web上还是在手机app上,我们都可以以游客的身份访问,此时都会有登录/注册字眼,当我们登录之后,就会是我们的 ...

  7. 集合(set)的基本操作

    集合是一个无序的,不重复的数据组合,它的主要作用如下: 去重,把一个列表变成集合,就自动去重了 集合中的元素必须是不可变类型 关系测试,测试两组数据之前的交集.差集.并集等关系 常用操作 a = se ...

  8. ES6 学习3 函数

    1.函数默认参数 在ES5我们给函数定义参数默认值是怎么样? function action(num) { num = num || 200 //当传入num时,num为传入的值 //当没传入参数时, ...

  9. matplotlib bar函数重新封装

    参考: https://blog.csdn.net/jenyzhang/article/details/52047557 https://blog.csdn.net/liangzuojiayi/art ...

  10. 关于iptables允许samba的问题

    今天同事跟我说他们部门的共享不能用了,想了想,最近变更的只有iptables,于是看看是否是这个原因,发现没有允许samba的入站和出站规则,我的iptables规则默认是所有都drop的,但是不知确 ...