Rafy

stay Foolish , stay Hungry

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

题目链接: http://pat.zju.edu.cn/contests/pat-practise/1003

这道题目是让求图中两节点之间的最短路径条数,同时求出这些最短路径中权值相加最大值,可以通过修改Dijkstra算法解题,不过我用的是深度优先搜索,书上总是说递归的程序比非递归程序容易看懂,而且逻辑也符合正常思维方式,可我却对递归结构很不感冒,确实,递归随随便便5行代码,可能用栈需要20+行才能模拟出来,但是我还是偏好于非递归实现,至少我觉得这个符合自己的思维习惯,话说回来,不用DJ,而采用深搜解这道题,也是因为深搜更容易想到而且能够想通,毕竟,暴力是蛮荒时代的本色,而能想出巧力的头脑都是苹果砸出来的。

深搜的思路是:从start结点出发,采用深度优先搜索方式,遍历整个图,记录下start到end的所有路径,只要遇到end结点,就认为这条深搜路径完成,将cost和saveTeam两个结果存至road中,然后回溯到上一个结点,继续深搜,以寻找其它能够到达end的路径,当把所有可能的路径寻找完以后(注意:所有的路径都是简单路径,不能存在环),将road按照cost大小进行排序,数出cost最小的相同值有几个,同时在这些cost相同的前提下,找到saveTeam的最大值,将这两个值数出,即为题目所求。

  1 /*使用深度优先搜索,如果搜索到目的结点,则回溯至上一个结点重新深度优先搜索*/
2 #include <stdio.h>
3 #include <stdlib.h>
4
5 typedef struct
6 {
7 int cost;//该条路径的长度
8 int number;//该条路径可以召集的救援组数目
9 }route;//结果的结构体,记录两节点之间的所有路径
10
11 typedef struct
12 {
13 int top;
14 int data[501];
15 }stk;
16
17 int edge[501][501];//邻接矩阵
18 route road[1000];//假设start和end之间最多有1000条不相同路径
19
20 int comp(const void *a, const void *b)
21 {
22 route c = *(route *)a;
23 route d = *(route *)b;
24 if(c.cost > d.cost) return 1;
25 else return -1;
26 }
27
28 int main()
29 {
30 int n;//城市数目
31 int m;//道路数目
32 int start;//当前所在城市
33 int end;//需要救援的城市
34 int *saveTeam;//每个城市的救援组数目
35 int pos;//road数组的游标
36 int tempcost, tempnumber;//cost和number两个变量的临时版本
37 int prenode;//dfs搜索时记录最近一次向下深搜的结点
38
39 int sum,max;
40
41 int i, j;
42 int c1, c2, l;
43 int final[501];
44 stk entry;//深搜栈
45 int k, t;
46
47 while(scanf("%d %d %d %d", &n, &m, &start, &end) != EOF)
48 {
49 for(i = 0; i < 501; i ++)
50 {
51 for(j = 0; j < 501; j ++)
52 {
53 edge[i][j] = 0;
54 }
55 }
56 saveTeam = (int *)malloc(n * sizeof(int));
57 for(i = 0; i < n; i ++)
58 {
59 scanf("%d", &saveTeam[i]);
60 }
61 for(i = 0; i < m; i ++)
62 {
63 scanf("%d %d %d", &c1, &c2, &l);
64 edge[c1][c2] = l;
65 edge[c2][c1] = l;
66 }
67 for(i = 0; i < n; i ++)
68 {
69 final[i] = 0;//都未访问
70 }
71 entry.top = 0;
72 entry.data[entry.top] = start;//源点入栈
73 entry.top ++;
74 final[start] = 1;
75 pos = 0;
76 tempcost = 0;
77 tempnumber = saveTeam[start];
78 prenode = -1;
79 while(entry.top != 0)
80 {
81 k = entry.data[entry.top - 1];
82 if(k == end)//队长现在在的城市就是需要救援的城市,即start == end,这个if块不加上会导致第二个案例WA
83 {
84 road[pos].cost = 0;
85 road[pos].number = saveTeam[k];
86 pos ++;
87 entry.top --;
88 continue;
89 }
90 for(i = prenode + 1; i < n; i ++)
91 {
92 if(final[i] == 0 && edge[k][i] != 0)
93 {
94 break;
95 }
96 }
97 if(i < n)//找到了向下深搜的结点
98 {
99 tempcost += edge[k][i];
100 tempnumber += saveTeam[i];
101 if(i == end)//该点是深搜的终点
102 {
103 road[pos].cost = tempcost;
104 road[pos].number = tempnumber;
105 pos ++;
106 //printf("pos = %d, cost = %d, number = %d\n",pos - 1, road[pos - 1].cost, road[pos - 1].number);
107 tempcost -= edge[k][i];
108 tempnumber -= saveTeam[i];//因为回溯到了上一个结点,所以要减去
109 prenode = i;
110 }
111 else//该点只是一个普通结点
112 {
113 entry.data[entry.top] = i;
114 entry.top ++;
115 final[i] = 1;
116 prenode = -1;
117 }
118 }
119 else//没有找到向下深搜的结点,需要回溯
120 {
121 t = entry.data[entry.top - 2];
122 tempcost -= edge[t][k];
123 tempnumber -= saveTeam[k];
124 prenode = k;
125 final[k] = 0;
126 entry.top --;
127 }
128 }
129 qsort(road, pos, sizeof(route), comp);
130 sum = 0;
131 max = 0;
132 for(i = 0; i < pos; i ++)
133 {
134 if(road[i].cost == road[0].cost)
135 {
136 sum ++;
137 if(road[i].number > max)
138 {
139 max = road[i].number;
140 }
141 }
142 else
143 {
144 break;
145 }
146 }
147 printf("%d %d\n",sum, max);
148
149 }
150 return 0;
151 }



posted on 2012-03-16 10:34  Rafy  阅读(1584)  评论(0编辑  收藏  举报