1. 程式人生 > >「美團 CodeM 初賽 Round B」送外賣2---------------狀壓dp

「美團 CodeM 初賽 Round B」送外賣2---------------狀壓dp

題目描述

一張 n 個點 m 條有向邊的圖上,有 q  個配送需求,需求的描述形式為 (si,ti,li,ri)( s_i , t_i , l_i , r_i )(si,ti,li,ri),即需要從點 si 送到 ti, 在時刻 li 之後(包括 lil_ili )可以在 sis_isi 領取貨物,需要在時刻 ri 之前(包括 ri)送達 ti ,每個任務只需完成一次。

圖上的每一條邊均有邊權,權值代表通過這條邊消耗的時間。在時刻 000 有一個工作人員在點 1 上,求他最多能完成多少個配送任務。

在整個過程中,可以認為領貨跟交貨都是不消耗時間的,時間只花費在路程上。當然在一個點逗留也是允許的。

 

輸出格式

一個整數,表示最多能完成的任務數量。

樣例輸入

5 4 3
1 2 1
2 3 1
3 4 1
4 5 1
1 2 3 4
2 3 1 2
3 4 3 4

樣例輸出

2

樣例解釋

工作人員可以在時刻 1 到達點 2 ,領取第二個貨物後在時刻 2 到達點 3 後交貨,逗留到時刻 4 ,領取第三個貨物,在時刻 4 到達點 4 並交貨。

 

 

    •   首先的首先,需要明確配送的方式。在配送的途中手中不一定只有一份外賣!

        然後出於對資料的敏感,易想到用進位制數表示狀態。

   •   

由於每一份外賣有按照程式有三種狀態,所以用三進製表示外賣的整體狀態,

        在dp陣列中作為一個維度,剩下時間和當前位置。

        •    由於時間是資料中最大的存在,成為了dp的物件,當前位置成為了另一個狀

             態維度。

   •    轉移的話,只是合法性的判斷了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,q,x,y,z;
 4 int dis[25][25];
 5 int f[60050][25],w,now,ans;
 6 int base[15],s[15],t[15],l[15],r[15];
 7 int main()
 8 {
 9     base[0]=1;
10     for(int i=1;i<=11;++i)
11         base[i]=base[i-1]*3;
12     memset(dis,0x3f,sizeof(dis));
13     memset(f,0x3f,sizeof(f));f[0][1]=0;
14     scanf("%d%d%d",&n,&m,&q);
15     for(int i=1;i<=m;++i)
16     {
17         scanf("%d%d%d",&x,&y,&z);
18         dis[x][y]=min(dis[x][y],z);
19     }
20     for(int i=1;i<=n;++i)
21         dis[i][i]=0;
22     for(int k=1;k<=n;++k)
23         for(int i=1;i<=n;++i)
24             for(int j=1;j<=n;++j)
25                 dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
26     for(int i=0;i<q;++i)
27         scanf("%d%d%d%d",&s[i],&t[i],&l[i],&r[i]);
28     m=base[q]-1;
29     for(int i=0;i<=m;++i)
30     {
31         for(int j=1;j<=n;++j)
32         {
33             for(int k=0;k<q;++k)
34             {
35                 now=i/base[k]%3;
36                 if(now==0)
37                     f[i+base[k]][s[k]]=min(f[i+base[k]][s[k]],max(f[i][j]+dis[j][s[k]],l[k]));
38                 else if(now==1&&f[i][j]+dis[j][t[k]]<=r[k])
39                     f[i+base[k]][t[k]]=min(f[i+base[k]][t[k]],f[i][j]+dis[j][t[k]]);
40                 
41             }
42             if(f[i][j]<f[0][0])
43             {
44                 w=0;
45                 for(int k=0;k<=10;++k)
46                     if(i/base[k]%3==2)
47                         ++w;
48                 ans=max(ans,w);
49             }
50         }
51     }
52     printf("%d",ans);
53     return 0;
54 }
程式碼1
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,q,x,y,z;
 4 int dis[25][25];
 5 int f[60050][25],w,now,ans;
 6 int base[15],s[15],t[15],l[15],r[15];
 7 int main()
 8 {
 9     base[0]=1;
10     for(int i=1;i<=11;++i)
11         base[i]=base[i-1]*3;
12     memset(dis,0x3f,sizeof(dis));
13     memset(f,0x3f,sizeof(f));f[0][1]=0;
14     scanf("%d%d%d",&n,&m,&q);
15     for(int i=1;i<=m;++i)
16     {
17         scanf("%d%d%d",&x,&y,&z);
18         dis[x][y]=min(dis[x][y],z);
19     }
20     for(int i=1;i<=n;++i)
21         dis[i][i]=0;
22     for(int k=1;k<=n;++k)
23         for(int i=1;i<=n;++i)
24             for(int j=1;j<=n;++j)
25                 dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
26     for(int i=0;i<q;++i)
27         scanf("%d%d%d%d",&s[i],&t[i],&l[i],&r[i]);
28     m=base[q]-1;
29     for(int i=0;i<=m;++i)
30     {
31         for(int j=1;j<=n;++j)
32         {
33             if(f[i][j]==f[0][0])
34                 continue;
35             for(int k=0;k<q;++k)
36             {
37                 now=i/base[k]%3;
38                 if(now==0)
39                     f[i+base[k]][s[k]]=min(f[i+base[k]][s[k]],max(f[i][j]+dis[j][s[k]],l[k]));
40                 else if(now==1&&f[i][j]+dis[j][t[k]]<=r[k])
41                     f[i+base[k]][t[k]]=min(f[i+base[k]][t[k]],f[i][j]+dis[j][t[k]]);
42                 
43             }
44             w=0;
45             for(int k=0;k<=10;++k)
46                 if(i/base[k]%3==2)
47                     ++w;
48             ans=max(ans,w);
49         }
50     }
51     printf("%d",ans);
52     return 0;
53 }
程式碼2

       這兩份程式碼在思路上是完全一致的。但是……

           相似的結果還發生在另一個狀壓題上(第二份程式碼直接是TLE 了):

    這究竟是種怎樣的操作?

    如果當前狀態完全不可能被轉移到的話,就完全沒必要對它進行暴力擴充套件了,果斷continue。