1. 程式人生 > >逛公園 [NOIP2017 D1T3] [記憶化搜索]

逛公園 [NOIP2017 D1T3] [記憶化搜索]

dash lin -i 取模 分享 方案 -s res 同學

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

2
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

3
-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\n",ans);
107     }
108     return 0;
109 }
View Code

逛公園 [NOIP2017 D1T3] [記憶化搜索]