UVA-10917 Walk Through the Forest (dijkstra+DP)
题目大意:n个点,m条边的无向图。一个人从起点到终点按照下面的走法:从A走向B当A到终点的最小距离比B到终点的最小距离大时。问从起点到终点有多少路径方案。
题目分析:先用dijkstra预处理出终点到每个点的最短路,然后将满足行走条件的A、B(除行走条件外,还要满足一个前提,即A、B之间要有边)用一条有向边连起来(A->B),得到一个DAG,动态规划解决。
代码如下:
# include<iostream> # include<cstdio> # include<vector> # include<queue> # include<cstring> # include<algorithm> using namespace std; # define LL long long const LL INF=0x7fffffffffffffff; struct Node { int u; LL d; Node(int _u,LL _d):u(_u),d(_d){} bool operator < (const Node &a) const { return d>a.d; } }; struct Edge { int to,nxt,w; }; Edge e[200005]; int head[1005],n,cnt,vis[1005],dp[1005],mp[1005][1005]; LL dist[1005]; vector<int>G[1005]; void add(int u,int v,int w) { e[cnt].to=v; e[cnt].w=w; e[cnt].nxt=head[u]; head[u]=cnt++; } void dijkstra(int S) { memset(vis,0,sizeof(vis)); fill(dist,dist+n+1,INF); dist[S]=0; priority_queue<Node>q; q.push(Node(S,0)); while(!q.empty()) { Node u=q.top(); q.pop(); if(vis[u.u]) continue; vis[u.u]=1; for(int i=head[u.u];i!=-1;i=e[i].nxt){ int v=e[i].to; if(dist[v]>u.d+e[i].w){ dist[v]=u.d+e[i].w; if(!vis[v]) q.push(Node(v,dist[v])); } } } } int DP(int u) { if(dp[u]!=-1) return dp[u]; if(u==2) return dp[u]=1; int sum=0; for(int i=0;i<G[u].size();++i) sum+=DP(G[u][i]); return dp[u]=sum; } int main() { int a,b,c,m; while(scanf("%d",&n)&&n) { cnt=0; memset(head,-1,sizeof(head)); memset(mp,0,sizeof(mp)); scanf("%d",&m); while(m--) { scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); mp[a][b]=mp[b][a]=1; } dijkstra(2); for(int i=0;i<=n;++i) G[i].clear(); for(int i=1;i<=n;++i){ for(int j=i+1;j<=n;++j){ if(!mp[i][j]) continue; if(dist[i]>dist[j]) G[i].push_back(j); if(dist[i]<dist[j]) G[j].push_back(i); } } memset(dp,-1,sizeof(dp)); printf("%d\n",DP(1)); } return 0; }