HDU 1142 A Walk Through the Forest (dijkstra算法)
地址:http://acm.hdu.edu.cn/showproblem.php?pid=1142
思路1:
题目大意是给你一个图。起点为1,终点为2
然后点a到点b是合法的判断(Notice 1:)是当b存在一个到终点的距离小于a到终点的最小距离,求从起点到终点的路径数。
Notice 1:不合法并非是断路,合法指回家的时候只按dis[b] < dis[a]的路线走、
dis[]表示到终点2的最短路径, 满足dis[b] < dis[a], 表示这样a->b的是可选择的。 就是说每次回家时选择从距起点(最短距离)近的点 向 距起点(最短距离)远的点走, 求这样的路线条数。
dp[i] = sum{ dp[j] | i->j邻接 && dp[j] > dp[i]};
//即邻接的两点(i,j)且 i->j 的路线是可行的,到 j 的路径数是其所以前驱点路径数之和
for (j = 1; j <= n; j++)
{
if (i->j 邻接 且 dis[j] > dis[i])
{
then i->j的路线是可选择的;
dp[i] += dp[j];
}
}
借鉴代码1如下:
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <queue> 5 #include <algorithm> 6 using namespace std; 7 #define INF 0x7fffffff //这个是把inf赋值为一个极大值。你可以这样认为0x7fffffff是十六进制的-1,那么把它减1就相当于正的最大值 8 #define MAXN 1010 9 int map[MAXN][MAXN]; 10 int dis[MAXN]; 11 int dp[MAXN]; 12 bool hash[MAXN]; 13 struct Dij 14 { 15 int id; 16 int dis; 17 bool friend operator < (const Dij a, const Dij b) 18 { 19 return a.dis > b.dis; 20 } 21 }; 22 Dij now, next; 23 void Init(int n) 24 { 25 for (int i = 0; i <= n; i++) 26 { 27 map[i][i] = 0; 28 for (int j = i + 1; j <= n; j++) 29 { 30 map[i][j] = map[j][i] = INF; 31 } 32 } 33 } 34 void Bfs(int st, int n) 35 { 36 memset(hash, false, sizeof(hash)); 37 for (int i = 1; i <= n; i++) 38 { 39 dis[i] = INF; 40 } 41 priority_queue<Dij> Q; 42 now.id = st; 43 now.dis = 0; 44 dis[st] = 0; 45 Q.push(now); 46 47 while (!Q.empty()) 48 { 49 now = Q.top(); 50 Q.pop(); 51 if (hash[now.id]) 52 { 53 continue; 54 } 55 hash[now.id] = true; 56 57 for (int j = 1; j <= n; j++) 58 { 59 if (!hash[j] && map[now.id][j] != INF && 60 dis[j] > dis[now.id] + map[now.id][j]) 61 { 62 dis[j] = dis[now.id] + map[now.id][j]; 63 next.id = j; 64 next.dis = dis[j]; 65 Q.push(next); 66 } 67 } 68 } 69 } 70 int dp_num(int ed, int n) 71 { 72 if (dp[ed] != 0) 73 {//不为0,说明已求得,直接返回。 74 return dp[ed]; 75 } 76 for (int j = 1; j <= n; j++) 77 { 78 if (j != ed && map[j][ed] != INF) 79 { 80 if (dis[j] < dis[ed]) 81 { 82 dp[ed] += dp_num(j, n); 83 //dis表示到终点2的最短路径,即按题意求dis[b] < dis[a]的路径数目。 84 } 85 } 86 } 87 return dp[ed]; 88 } 89 int main() 90 { 91 int n, m, i, j; 92 int a, b, c; 93 while (scanf("%d", &n) != EOF) 94 { 95 if (n == 0) 96 break; 97 Init(n); 98 scanf("%d", &m); 99 for (i = 0; i < m; i++) 100 { 101 scanf("%d %d %d", &a, &b, &c); 102 if (c < map[a][b]) 103 { 104 map[a][b] = map[b][a] = c; 105 } 106 } 107 Bfs(2, n); 108 memset(dp, 0, sizeof(dp)); 109 dp[2] = 1;//只要dis表示到终点2的最短路即可,dfs可以从起点->终点,也可以从终点->起点 110 dp_num(1, n);//dfs求路径数 111 printf("%d/n", dp[1]); 112 } 113 return 0; 114 }
借鉴代码2如下:
1 #include<stdio.h> 2 int n,map[1001][1001]; 3 int dist[1001],s[1001],dp[1001]; 4 int dfs(int v)//深搜 5 { 6 int i,temp,sum=0; 7 if(dp[v]!=-1) 8 return dp[v]; 9 if(v==2) 10 return 1; 11 for(i=1;i<=n;i++) 12 { 13 if(map[v][i]!=2000000&&dist[v]>dist[i])// 14 { 15 temp=dfs(i); 16 sum+=temp; 17 } 18 } 19 dp[v]=sum; 20 return sum; 21 } 22 void dijkstra(int v)//dijkstra求最短路 23 { 24 int i,j,u,min; 25 for(i=1;i<=n;i++) 26 dist[i]=map[v][i]; 27 dist[v]=0; 28 s[v]=1; 29 for(i=1;i<n;i++) 30 { 31 min=2000000; 32 for(j=1;j<=n;j++) 33 { 34 if(!s[j]&&dist[j]<min) 35 { 36 min=dist[j]; 37 u=j; 38 } 39 } 40 s[u]=1; 41 for(j=1;j<=n;j++) 42 { 43 if(!s[j]&&dist[j]>dist[u]+map[u][j]) 44 { 45 dist[j]=dist[u]+map[u][j]; 46 } 47 } 48 } 49 } 50 int main() 51 { 52 int i,j,x,m; 53 while(scanf("%d",&n),n) 54 { 55 for(i=1;i<=n;i++) 56 { 57 s[i]=0; 58 dp[i]=-1; 59 for(j=1;j<=n;j++) 60 map[i][j]=2000000; 61 } 62 scanf("%d",&m); 63 while(m--) 64 { 65 scanf("%d%d%d",&i,&j,&x); 66 map[i][j]=map[j][i]=x; 67 } 68 dijkstra(2); 69 dfs(1); 70 printf("%d/n",dp[1]); 71 } 72 return 0; 73 }
思路2:
本题的思想就是dfs+dijkstra。本题的意思是,如果在点B出存在一条路使得从B点出发可以比从A点出发跟快的到达home,所以B到home的最短距离要比A到home得最短距离小,所以本题首先要求出各点到home得距离,然后再用记忆搜索法搜索即可
借鉴代码如下:
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 using namespace std; 5 int dist[1005],dp[1005]; 6 typedef struct t 7 { 8 int end,len; 9 struct t *next; 10 }T; 11 struct node 12 { 13 int data; 14 int len; 15 bool operator <(const node &a)const 16 { 17 return a.len<len; 18 } 19 T *next; 20 }s[1005]; 21 void dijkstra(int v0) 22 { 23 s[v0].len=0;node cur; 24 int visit[1005],mark=0; 25 memset(visit,0,sizeof(visit)); 26 memset(dist,-1,sizeof(dist)); 27 priority_queue<node> qu; 28 qu.push(s[v0]); 29 dist[v0]=0; 30 while(!qu.empty ()) 31 { 32 cur=qu.top(); 33 while(visit[cur.data]) 34 { 35 qu.pop(); 36 if(qu.empty ()) 37 { 38 mark=1; 39 break; 40 } 41 cur=qu.top(); 42 } 43 if(mark) 44 break; 45 qu.pop(); 46 visit[cur.data]=1; 47 T *p=cur.next; 48 while(p) 49 { 50 if(!visit[p->end]) 51 { 52 if(dist[p->end]==-1||dist[cur.data]+p->len<dist[p->end] ) 53 s[p->end].len=dist[p->end]=p->len+dist[cur.data]; 54 qu.push (s[p->end]); 55 } 56 p=p->next; 57 } 58 } 59 } 60 int dfs(int v0) 61 { 62 int temp=0; 63 if(v0==2) 64 return 1; 65 if(dp[v0]!=-1) 66 return dp[v0]; 67 t *p=s[v0].next; 68 while(p) 69 { 70 if(dist[v0]>dist[p->end]) 71 { 72 dp[p->end]=dfs(p->end); 73 temp+=dp[p->end]; 74 } 75 p=p->next; 76 } 77 return temp; 78 } 79 int main() 80 { 81 int n,i,m,a,b,len; 82 while(scanf("%d",&n)!=EOF) 83 { 84 if(n==0) 85 break; 86 scanf("%d",&m); 87 T *p,*q; 88 for(i=1;i<=n;i++) 89 { 90 s[i].next=NULL; 91 s[i].data=i; 92 } 93 memset(dp,-1,sizeof(dp)); 94 for(i=1;i<=m;i++) 95 { 96 scanf("%d%d%d",&a,&b,&len); 97 p=(T*)malloc(sizeof(T)); 98 p->end=b; 99 p->len=len; 100 p->next=s[a].next; 101 s[a].next=p; 102 q=(T*)malloc(sizeof(T)); 103 q->end=a; 104 q->len=len; 105 q->next=s[b].next; 106 s[b].next=q; 107 } 108 dijkstra(2); 109 printf("%d\n",dfs(1)); 110 } 111 return 0; 112 }
思路3:
题目大意是给一个图。起点为1,终点为2
然后点a到点b是合法的判断是当b存在一个到终点的距离小于a到终点的最小距离。。。。。求从起点到终点的路径数。。
我的做法是dijk + sort + dp。
先dijk出任何点到2的最小距离。然后按照距离对他们sort 。
dp就是很普通的路径dp:ans[终点] += ans[起点];
借鉴代码如下:
1 #include<iostream> 2 #include<algorithm> 3 #include<queue> 4 using namespace std; 5 #define MAXN 1100 6 #define INF 1000000000 7 8 struct way 9 { 10 int s; 11 int d;//distance 12 bool operator <(const way k)const 13 { 14 return d < k.d; 15 } 16 }; 17 18 struct point//restore id and d(distance) of each point 19 { 20 int d,id; 21 bool operator<(const point &a) const//used for sort 22 { 23 if(d==a.d) 24 return a.id>id;//从小到大排id 25 return a.d<d;//从大到小排distance 26 } 27 }p[MAXN]; 28 29 int n,ans[MAXN]; 30 int map[MAXN][MAXN]; 31 bool flag[MAXN]; 32 33 void dijk()//dijk find minimal distance between each point to point 2 34 { 35 priority_queue<way>Q; 36 37 way temp,now; 38 now.s=2; 39 now.d=0; 40 Q.push(now); 41 p[2].d=0; 42 43 while(!Q.empty()) 44 { 45 now=Q.top(); 46 Q.pop();//use priority queue to ensure pop the point with minimal distance every time 47 if(flag[now.s]) 48 continue; 49 flag[now.s]=1;//flag[i]==1 means it is in the end point set 50 for(int i=1;i<=n;i++)//从终点往回推 51 { 52 if(!flag[i]&&map[now.s][i]!=INF&&p[i].d>p[now.s].d+map[now.s][i]) 53 { 54 temp.s=i; 55 temp.d=p[now.s].d+map[now.s][i]; 56 p[i].d=temp.d; 57 Q.push(temp); 58 } 59 } 60 } 61 } 62 63 void init(int m)//初始化 64 { 65 int i,j; 66 int a,b,c; 67 for(i=1;i<=n;i++) 68 { 69 p[i].id=i; 70 flag[i]=0; 71 p[i].d=INF; 72 ans[i]=0; 73 for(j=1;j<=n;j++) 74 map[i][j]=INF; 75 } 76 while(m--) 77 { 78 scanf("%d%d%d",&a,&b,&c); 79 map[a][b] = c; 80 map[b][a] = c; 81 } 82 } 83 84 void dp()//ans[end point]+=ans[start point] 85 { 86 int i,j; 87 for(i=1;i<=n;i++)//find start point 1 88 if(p[i].id==1) 89 break; 90 ans[1]=1; 91 for(i;i<n;i++) 92 { 93 for(j=i+1;j<=n;j++)//p[j].d must be <= p[i].d after sorting 94 { 95 if(map[p[j].id][p[i].id]!=INF&&p[j].d<p[i].d) 96 ans[p[j].id]+=ans[p[i].id]; 97 } 98 } 99 } 100 101 int main() 102 { 103 int m; 104 while(scanf("%d",&n)!=EOF&&n!=0) 105 { 106 scanf("%d",&m); 107 init(m); 108 dijk();//find minimal distance between each point to point 2 109 sort(p+1,p+n+1);//sort the distance 110 dp(); 111 printf("%d/n",ans[2]); 112 } 113 return 0; 114 }