【Luogu1608】路徑統計(最短路)(DP)
阿新 • • 發佈:2017-12-28
要花 include dijkstra main std mar 行為 不能 總數
題目傳送門
題目描述
“RP餐廳”的員工素質就是不一般,在齊刷刷的算出同一個電話號碼之後,就準備讓HZH,TZY去送快餐了,他們將自己居住的城市畫了一張地圖,已知在他們的地圖上,有N個地方,而且他們目前處在標註為“1”的小鎮上,而送餐的地點在標註為“N”的小鎮。(有點廢話)除此之外還知道這些道路都是單向的,從小鎮I到J需要花費D[I,J]的時間,為了更高效快捷的將快餐送到顧客手中,
他們想走一條從小鎮1到小鎮N花費最少的一條路,但是他們臨出發前,撞到因為在路上堵車而生氣的FYY,深受啟發,不能僅知道一條路線,萬一。。。,於是,他們邀請FYY一起來研究起了下一個問題:這個最少花費的路徑有多少條?
輸入格式
輸入文件第一行為兩個空格隔開的數N,E,表示這張地圖裏有多少個小鎮及有多少邊的信息。
下面E行,每行三個數I、J、C,表示從I小鎮到J小鎮有道路相連且花費為C.(註意,數據提供的邊信息可能會重復,不過保證I<>J,1<=I,J<=n)。
輸出格式
輸出文件包含兩個數,分別是最少花費和花費最少的路徑的總數.
兩個不同的最短路方案要求:路徑長度相同(均為最短路長度)且至少有一條邊不重合。
若城市N無法到達則只輸出一個(‘No answer’);
輸入樣例
5 4 1 5 4 1 2 2 2 5 2 4 1 1
輸出樣例
4 2
題解 & 吐槽
這道題是一個很經典的最短路計數問題。
第一問可以直接SPFA/Dijkstra跑出來。
第二問是DP。
但是如果第二問用遞推來搞的話。。。需要先跑一遍拓撲排序呀。。。太麻煩了呀。。。
所以我們可以采用記憶化搜索。
Code
#include <bits/stdc++.h> using namespace std; const int max_n=2000+5,max_m=4000000+5; int n,m,total,ans; int edge[max_n][max_n],dp[max_n],dis[max_n],book[max_n]; inline void SPFA() { int from,to,w; queue <int> q; dis[1]=0; q.push(1); book[1]=1; while(!q.empty()) { from=q.front(); q.pop(); book[from]=1; for(register int i=1;i<=n;++i) { to=i; w=edge[from][to]; if(dis[to]>dis[from]+w) { dis[to]=dis[from]+w; if(!book[to]) { book[to]=1; q.push(to); } } } } return; } inline int DP(int x) { if(dp[x]) { return dp[x]; } if(x==1) { return dp[x]=1; } for(register int i=1;i<=n;++i) { if(dis[x]==dis[i]+edge[i][x]) { dp[x]+=DP(i); } } return dp[x]; } int main() { memset(dis,0x3f,sizeof(dis)); memset(edge,0x3f,sizeof(edge)); int x,y,z; scanf("%d %d",&n,&m); for(register int i=1;i<=m;++i) { scanf("%d %d %d",&x,&y,&z); edge[x][y]=min(edge[x][y],z); } SPFA(); DP(n); if(dis[n]^0x3f3f3f3f) { printf("%d %d\n",dis[n],DP(n)); } else { puts("No answer"); } return 0; }
【Luogu1608】路徑統計(最短路)(DP)