SGU145:Strange People

——problem:起点到终点的严格K短路(每个点在路径中最多出现一次)

——solution:二分+dfs+dijkstra优化

——url:http://acm.sgu.ru/problem.php?contest=0&problem=145

一开始以为A*就可以了。

鉴于A*本来也不会,所以就先学了遍A*。

写完发现A*求的是非严格最短路。

最后是二分答案+dfs+dijkstra优化过的。

注意:

1、当当前长度搜到的路径数已经大于K的话,就没必要再搜下去了。不过这样做的话,每次都要初始化下VIS数组。

2、用dijkstra求出终点到各点的最短路,用来在DFS的时候剪枝。

3、注意二分的问题,如果sum<=k,right=mid而不是mid-1。这是因为有多条路径是同一个长度。

如此可以保证最后小于right长度的路径数一定恰好大于等于K。

View Code
1 #include<stdio.h>
2 #include<memory.h>
3 #include<queue>
4  using namespace std;
5  #define V 105
6  #define E 40000
7  #define oo 0xfffffff
8 int head[V], nxt[E], ev[E], ew[E], pre[V], out[V], dist[V];
9 int u, v, l, n, m, sum, len, i, num, s, t, left, right, mid, k, total, ans;
10 bool vis[V], find;
11 struct node
12 {
13 int u, l;
14 friend bool operator <(node a, node b)
15 {
16 return a.l > b.l;
17 }
18 node(int a = 0, int b = 0) :
19 u(a), l(b)
20 {
21 }
22 } x, y;
23 void add_edge(int u, int v, int l)
24 {
25 nxt[++num] = head[u];
26 head[u] = num;
27 ev[num] = v;
28 ew[num] = l;
29 }
30 void dijkstra()
31 {
32 int i;
33 priority_queue<node> q;
34 memset(vis, 0, sizeof(vis));
35 for (i = 1; i <= n; i++)
36 dist[i] = oo;
37 dist[t] = 0;
38 q.push(node(t, 0));
39 while (!q.empty())
40 {
41 x = q.top();
42 q.pop();
43 if (!vis[x.u])
44 {
45 vis[x.u] = true;
46 for (i = head[x.u]; i; i = nxt[i])
47 {
48 y.u = ev[i];
49 y.l = x.l + ew[i];
50 if (y.l < dist[y.u])
51 {
52 dist[y.u] = y.l;
53 q.push(y);
54 }
55 }
56 }
57 }
58 }
59 void dfs(int u, int target, int limit)
60 {
61 int i;
62 if (u == target || find)
63 {
64 if (len <= limit)
65 sum++;
66 if (sum > k) //剪枝
67 find = true;
68 return;
69 }
70 if (len + dist[u] > limit)
71 return;
72 for (i = head[u]; i; i = nxt[i])
73 if (!vis[ev[i]])
74 {
75 len += ew[i];
76 vis[ev[i]] = true;
77 if (len <= limit)
78 dfs(ev[i], target, limit);
79 if (find)
80 return;
81 len -= ew[i];
82 vis[ev[i]] = false;
83 }
84 }
85 void find_the_path(int u, int target, int limit)
86 {
87 int i;
88 if (u == target || find)
89 {
90 if (len == limit)
91 {
92 total = 0;
93 i = target;
94 while (i != s)
95 {
96 out[++total] = i;
97 i = pre[i];
98 }
99 out[++total] = s;
100 find = true;
101 }
102 return;
103 }
104 if (len + dist[u] > limit)
105 return;
106 for (i = head[u]; i; i = nxt[i])
107 if (!vis[ev[i]])
108 {
109 len += ew[i];
110 vis[ev[i]] = true;
111 pre[ev[i]] = u;
112 if (len <= limit)
113 find_the_path(ev[i], target, limit);
114 if (find)
115 return;
116 len -= ew[i];
117 vis[ev[i]] = false;
118 }
119 }
120 int main()
121 {
122 scanf("%d%d%d", &n, &m, &k);
123 num = 0;
124 memset(head, 0, sizeof(head));
125 memset(nxt, 0, sizeof(nxt));
126 for (i = 0; i < m; i++)
127 {
128 scanf("%d%d%d", &u, &v, &l);
129 add_edge(u, v, l);
130 add_edge(v, u, l);
131 }
132 scanf("%d%d", &s, &t);
133 dijkstra();
134 left = 0;
135 right = oo;
136 while (left < right)
137 {
138 mid = (left + right) / 2;
139 memset(vis, 0, sizeof(vis));
140 vis[s] = true;
141 find = false;
142 sum = 0;
143 len = 0;
144 dfs(s, t, mid);
145 if (sum < k)
146 left = mid + 1;
147 if (sum >= k)
148 right = mid; //这里要注意right的值。
149 }
150 ans = right;
151 find = false;
152 memset(vis, 0, sizeof(vis));
153 vis[s] = true;
154 len = 0;
155 find_the_path(s, t, ans);
156 printf("%d %d\n", ans, total);
157 for (i = total; i > 1; i--)
158 printf("%d ", out[i]);
159 printf("%d\n", out[1]);
160 return 0;
161 }

posted on 2011-03-27 15:29  风也轻云也淡  阅读(290)  评论(0编辑  收藏  举报