zoukankan      html  css  js  c++  java
  • 逛公园 [NOIP2017 D1T3] [记忆化搜索]

    Description

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

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

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

    策策同学想知道总共有多少条满足条件的路线,你能帮帮他吗? 为避免输出过大,答案对P取模。 如果有无穷多条合法的路线,请输出−1。

    Input

    第一行包含一个整数 T, 代表数据组数。 接下来T组数据,对于每组数据:

    第一行包含四个整数 N,M,K,P,每两个整数之间用一个空格隔开。

    接下来M行,每行三个整数ai,bi,ci,代表编号为ai、bi的点之间有一条权值为ci的有向边,每两个整数之间用一个空格隔开。

    Output

    包含T行,每行一个整数代表答案。

    Sample Input


    5 7 2 10 
    1 2 1 
    2 4 0 
    4 5 2 
    2 3 2 
    3 4 1 
    3 5 2 
    1 5 3 
    2 2 0 10 
    1 2 0 
    2 1 0

    Sample Output


    -1

    说明

    【样例解释1】

    对于第一组数据,最短路为 3 。 1 – 5, 1 – 2 – 4 – 5, 1 – 2 – 3 – 5 为 3条合法路径。

    【测试数据与约定】

    对于不同的测试点,我们约定各种参数的规模不会超过如下

    测试点编号  TT    NN    MM    KK    是否有0边
    1 5 5 10 0
    2 5 1000 2000 0
    3 5 1000 2000 50
    4 5 1000 2000 50
    5 5 1000 2000 50
    6 5 1000 2000 50
    7 5 100000 200000 0
    8 3 100000 200000 50
    9 3 100000 200000 50
    10 3 100000 200000 50


    数据保证:至少存在一条合法的路线。

    分析
    我真的是太弱了,考场上写了一个A星,结果过的全是K=0的,然后就只有30分了(t1t2已让我心态爆炸
    )

    我们看数据,K≤50,我们可以比较容易地想到dp,如何设状态?

    我们记dis[u]为u点到n的最短路,我们走完一条方案希望整个距离不超过dis[1]+K

    那我们就记录下到每个点的剩余额度rem,我们希望剩余额度尽可能大,就有更多精力走更多的路

      对于一条边edge(u,v,val)

      如果不走这条边,从u出发的最小代价为dis[u](记录最小代价就是为了剩余额度尽可能大,到下个路口有更多的选择)

      如果我们走了这条边,从u出发的最小代价为val+dis[v]

      那么剩余额度就是rem-(dis[v]+val-dis[u]),如果(dis[v]+val-dis[u])>rem 此方案无效

    那么我们看出来方案数和当前所在的点u和剩余额度rem有关,那么我们记录方案数为dp[u][rem],根据上面分析可以知道dp[u][rem]+=dp[v][rem-(dis[v]+val-dis[u])],记忆化搜索即可。

    到了终点不论剩余额度是多少,一开始给了k的额度,只要最后的额度≥0即可。

    如何对付0边?记录下状态vis[u][rem]即可,如果再次访问就返回-1

    代码

      1 #include<set>
      2 #include<map>
      3 #include<queue>
      4 #include<stack>
      5 #include<cmath>
      6 #include<cstdio>
      7 #include<cstring>
      8 #include<iostream>
      9 #include<algorithm>
     10 #define RG register int
     11 #define rep(i,a,b)    for(RG i=a;i<=b;++i)
     12 #define per(i,a,b)    for(RG i=a;i>=b;--i)
     13 #define ll long long
     14 #define inf (1<<29)
     15 #define maxn 100005
     16 #define maxm 200005
     17 #define add(x,y,z) e[++cnt]=(E){y,head[x],z},head[x]=cnt
     18 using namespace std;
     19 int T,n,m,K,p,cnt,ans,flg;
     20 int head[maxn],vis[maxn][55],dp[maxn][55],dis[maxn];
     21 struct E{
     22     int v,next,val;
     23 }e[maxm];
     24 inline int read()
     25 {
     26     int x=0,f=1;char c=getchar();
     27     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
     28     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
     29     return x*f;
     30 }
     31 
     32 void init()
     33 {
     34     memset(head,0,sizeof(head));
     35     memset(dis,63,sizeof(dis));
     36     memset(vis,0,sizeof(vis));
     37     memset(dp,0,sizeof(dp));
     38     cnt=ans=flg=0;
     39 }
     40 
     41 inline int mod(int a){return a>=p?a-p:a;}
     42 
     43 namespace PRE{
     44 int head[maxn],vis[maxn],cnt;
     45 
     46 struct E{
     47     int v,next,val;
     48 }e[maxm];
     49 
     50 void ad(int x,int y,int z) {e[++cnt]=(E){y,head[x],z},head[x]=cnt;}
     51 
     52 void init(){memset(head,0,sizeof(head));cnt=0;}
     53 
     54 void spfa()
     55 {
     56     queue<int> que;que.push(n),dis[n]=0;
     57     RG u,v;
     58     while(!que.empty())
     59     {
     60         u=que.front(),que.pop();
     61         for(RG i=head[u];i;i=e[i].next)
     62         {
     63             v=e[i].v;
     64             if(dis[v]>dis[u]+e[i].val)
     65             {
     66                 dis[v]=dis[u]+e[i].val;
     67                 if(!vis[v])    vis[v]=1,que.push(v);
     68             }
     69         }
     70         vis[u]=0;
     71     }
     72 }
     73 
     74 }
     75 
     76 int dfs(int u,int rem)
     77 {
     78     if(dp[u][rem])    return dp[u][rem];
     79     if(vis[u][rem])    return dp[u][rem]=-1;
     80     vis[u][rem]=-1;
     81     int res,v,ret;
     82     if(u==n)    dp[u][rem]=1;
     83     for(int i=head[u];i;i=e[i].next)
     84     {
     85         v=e[i].v;
     86         res=dis[v]+e[i].val-dis[u];
     87         if(res>rem)    continue;
     88         if((ret=dfs(v,rem-res))==-1)    return dp[u][rem]=-1;
     89         dp[u][rem]=mod(ret+dp[u][rem]);
     90     }
     91     vis[u][rem]=0;
     92     return dp[u][rem];
     93 }
     94 
     95 int main()
     96 {
     97     freopen("data7.in","r",stdin);
     98     T=read();
     99     while(T--)
    100     {
    101         init();PRE::init();
    102         n=read(),m=read(),K=read(),p=read();
    103         for(RG i=1,u,v,val;i<=m;i++) u=read(),v=read(),val=read(),add(u,v,val),PRE::ad(v,u,val);
    104         PRE::spfa();
    105         memset(vis,0,sizeof(dp));
    106         ans=dfs(1,K);printf("%d
    ",ans);
    107     }
    108     return 0;
    109 }
    View Code
  • 相关阅读:
    数据库目录
    设计模式
    mysql的索引结构
    ElasticSearch的基本操作
    转:基于Hadoop 的分布式网络爬虫技术学习笔记
    爬虫 es 搜索引擎
    vue+django2.0.2-rest-framework 生鲜项目
    fiddler抓包时显示Tunnel to......443
    安装 Win10 + Ubuntu 双系统过程
    ROS 订阅者的创建及使用
  • 原文地址:https://www.cnblogs.com/ibilllee/p/9397751.html
Copyright © 2011-2022 走看看