標籤:c acm 演算法 c++ 圖論
分析:找到吉米從辦公室穿過森林回到家(也就是從點1到點2)的最短路徑有多少條,其中要滿足如果要走A到B這條路,那麼就有從A到終點的距離都大於B到終點的距離。
解法:spfa演算法+記憶化深搜
1、spfa求出從終點2到其他所有點的最短路
2、記憶化DFS從1開始向其他點深搜,最後結果就是dp[1]。
#include<iostream> #include<queue> using namespace std; int u[2000002];int v[2000002];int w[2000002];bool vis[1001];int d[1001];int first[1001];int Next[2000002];int dp[1001]; void Init(int n,int m) { int i; for(i=1;i<=n;i++) { vis[i]=false; first[i]=-1;dp[i]=-1; } for(i=0;i<m;i++) Next[i]=-1;}int DFS(int u){int i,sum;if(dp[u]!=-1) return dp[u]; //記憶化if(u==2) return 1; //終點sum=0;for(i=first[u];i!=-1;i=Next[i]){if(d[u]>d[v[i]])sum+=DFS(v[i]);}return dp[u]=sum;} void spfa(int n,int s){ queue<int> q; int i,x,y; for(i=1;i<=n;i++) d[i]=(i==s)?0:0x7fffffff; //初始化,自己到自己為0,其他到自己相當於無窮大 q.push(s); while(!q.empty()) { x=q.front(); q.pop(); vis[x]=false; for(i=first[x];i!=-1;i=Next[i]) { y=v[i]; if(d[y]>d[x]+w[i]) { d[y]=d[x]+w[i]; if(!vis[y]) { vis[y]=true; q.push(y); } } } } } void Read(int m) { int i,a,b; for(i=0;i<m;i++) { scanf("%d %d %d",&a,&b,&w[i]); u[i]=a; //儲存正向邊,因為是無向圖 v[i]=b; Next[i]=first[a]; first[a]=i; w[i+1]=w[i]; //儲存反向邊 i++; u[i]=b; v[i]=a; Next[i]=first[b]; first[b]=i; } } int main() { int n,m; while(scanf("%d",&n)==1 && n) { scanf("%d",&m); Init(n,m+m); //m+m是因為無向邊,每條都要儲存兩條 Read(m+m); spfa(n,2); //搜出2到其他所有點的最短路cout<<DFS(1)<<endl; //從1開始深搜,最終即為結果 } return 0; }
HDU ACM 1142 A Walk Through the Forest->SPFA演算法+記憶化深搜