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 }

你可能感兴趣的:(dijkstra)