//缩点+spfa
/*
*State: POJ3114     Accepted    2908K    375MS    C++    2953B
*题目大意:
*        给定一个有向有权图,然后要求求出图中任意两点间的最短距离。
*        注意图中可能有环,每一个环中的任意两点间的距离为0.
*解题思路:
*        题意看了好久,一开始还以为是lca,后来才发现那个奇怪的特征,
*        原来每个环中的任意两点间的距离为0,就说明要进行缩点了。缩点
*        之后还是要求最短距离,这个时候就想到了spfa.
*        总结就是: 缩点 + spfa
*解题感想:
*        从lca到缩点+spfa,感觉用缩点+spfa比较靠谱,但是估量了下,代码
*        长度可能要200行上下,不过还是稳稳地打了出来,之后经历了两次RE.
*        表示这么长的代码交出了RE是一件非常恐怖的事情。但好在代码里面,我
*        自己给自己留了条路,数组的初始值能赋值为-1的都赋值为-1,经过这条
*        后路查出了是我的tarjan_scc里面一个判断条件,判断son判断成了n.
*        就是缩点缩错了。最终2RE+1wa来到了最后的ac.泪奔~搞了两个钟。
*/
View Code
  1 #include <iostream>
  2 #include <vector>
  3 #include <cstdio>
  4 #include <queue>
  5 #include <utility>
  6 #include <stack>
  7 using namespace std;
  8 
  9 const int MAXN = 505;
 10 const int inf = 0x3f3f3f3f;
 11 
 12 typedef struct _node
 13 {
 14     int v, w;
 15 }N;
 16 
 17 vector<N> vec[MAXN];
 18 stack<int> S;
 19 int scc, dfn[MAXN], low[MAXN], step;
 20 int inS[MAXN], id[MAXN];
 21 
 22 //spfa
 23 vector<N> sccvec[MAXN];
 24 
 25 void deal_spfa(int n)
 26 {
 27     N tmp;
 28     int u, v;
 29     for(int i = 1; i <= n; i++)
 30     {
 31         for(unsigned j = 0; j < vec[i].size(); j++)
 32         {
 33             u = i, v = vec[i][j].v;
 34             if(id[u] == id[v])
 35                 continue;
 36             else
 37             {
 38                 tmp.v = id[v]; 
 39                 tmp.w = vec[i][j].w;
 40                 sccvec[id[u]].push_back(tmp);
 41             }
 42         }
 43     }
 44 }
 45 
 46 int spfa(int s, int e)
 47 {
 48     queue<int> Q;
 49     int dis[MAXN], in[MAXN] = {0};
 50     for(int i = 0; i < MAXN; i++)
 51         dis[i] = inf;
 52     dis[s] = 0;
 53     in[s] = 1;
 54     Q.push(s);
 55     while(!Q.empty())
 56     {
 57         int pre = Q.front();
 58         Q.pop();
 59         in[pre] = 0;
 60         for(unsigned i = 0; i < sccvec[pre].size(); i++)
 61         {
 62             int son = sccvec[pre][i].v;
 63             int w = sccvec[pre][i].w;
 64             if(dis[son] > dis[pre] + w)
 65             {
 66                 dis[son] = dis[pre] + w;
 67                 if(in[son] == 0)
 68                 {
 69                     Q.push(son);
 70                     in[son] = 1;
 71                 }
 72             }
 73         }
 74     }
 75 
 76     return dis[e];
 77 }
 78 
 79 void init()
 80 {
 81     while(!S.empty())
 82         S.pop();
 83     step = 0;
 84     scc = 1;
 85     for(int i = 0; i < MAXN; i++)
 86     {
 87         sccvec[i].clear();
 88         id[i] = 0;
 89         inS[i] = 0;
 90         dfn[i] = low[i] = -1;
 91         vec[i].clear();
 92     }
 93 }
 94 
 95 void addEdge(int u, int v, int w)
 96 {
 97     N tmp;
 98     tmp.v = v, tmp.w = w;
 99     vec[u].push_back(tmp);
100 }
101 
102 void tarjan_scc(int n)
103 {
104     dfn[n] = low[n] = ++step;
105     S.push(n);
106     inS[n] = 1;
107     for(unsigned i = 0; i < vec[n].size(); i++)
108     {
109         int son = vec[n][i].v;
110         if(dfn[son] == -1)
111         {
112             tarjan_scc(son);
113             low[n] = min(low[n], low[son]);
114         }
115         else if(inS[son] == 1)
116         {
117             low[n] = min(low[n], dfn[son]);
118         }
119     }
120     if(low[n] == dfn[n] && !S.empty())
121     {
122         //cout << "--------------" << endl;
123         int tmp;
124         do
125         {
126             tmp = S.top();
127             //cout << tmp << " ";
128             S.pop();
129             inS[tmp] = 0;
130             id[tmp] = scc;
131         }while(!S.empty() && tmp != n);
132         //cout << endl;
133         scc++;
134     }
135 }
136 
137 int main(void)
138 {
139 #ifndef ONLINE_JUDGE
140     //freopen("in.txt", "r", stdin);
141 #endif
142     //cout << inf << endl;
143     int n, m, cas_c = 0;
144     while(scanf("%d", &n), n)
145     {
146         scanf("%d", &m);
147         if(cas_c++ != 0)
148             printf("\n");
149         int u, v, w;
150         init();
151         for(int i = 0; i < m; i++)
152         {
153             scanf("%d %d %d", &u, &v, &w);
154             addEdge(u, v, w);
155         }
156         for(int i = 1; i <= n; i++)
157         {
158             if(dfn[i] == -1)
159                 tarjan_scc(i);
160         }
161 
162         //cout << "******" << endl;
163         deal_spfa(n);
164         int q;
165         scanf("%d", &q);
166         for(int i = 0; i < q; i++)
167         {
168             scanf("%d %d", &u, &v);
169             if(id[u] == id[v])
170                 printf("0\n");
171             else
172             {
173                 int ans = spfa(id[u], id[v]);
174                 if(ans == inf)
175                     printf("Nao e possivel entregar a carta\n");
176                 else
177                     printf("%d\n", ans);
178             }
179         }
180     }
181     return 0;
182 }
183 
184 
185 
186 第二次优化时间
187 State: POJ3114    Accepted    3904K    313MS    C++    2878B
188 #include <iostream>
189 #include <vector>
190 #include <cstdio>
191 #include <queue>
192 #include <utility>
193 #include <stack>
194 using namespace std;
195 
196 const int MAXN = 505;
197 const int MAXE = 250005;
198 const int inf = 0x3f3f3f3f;
199 
200 typedef struct _node
201 {
202     int v, w;
203     int next;
204 }N;
205 
206 N edge[MAXE];
207 int scc, dfn[MAXN], low[MAXN], step, myS[MAXN], top;
208 int inS[MAXN], id[MAXN], cntEdge, head[MAXN];
209 
210 //spfa
211 vector<N> sccvec[MAXN];
212 
213 void deal_spfa(int n)
214 {
215     N tmp;
216     int u, v;
217     for(int i = 1; i <= n; i++)
218     {
219         for(int j = head[i]; j != -1; j = edge[j].next)
220         {
221             u = i, v = edge[j].v;
222             if(id[u] == id[v])
223                 continue;
224             else
225             {
226                 tmp.v = id[v]; 
227                 tmp.w = edge[j].w;
228                 sccvec[id[u]].push_back(tmp);
229             }
230         }
231     }
232 }
233 
234 int spfa(int s, int e)
235 {
236     queue<int> Q;
237     int dis[MAXN], in[MAXN] = {0};
238     for(int i = 0; i < MAXN; i++)
239         dis[i] = inf;
240     dis[s] = 0;
241     in[s] = 1;
242     Q.push(s);
243     while(!Q.empty())
244     {
245         int pre = Q.front();
246         Q.pop();
247         in[pre] = 0;
248         for(unsigned i = 0; i < sccvec[pre].size(); i++)
249         {
250             int son = sccvec[pre][i].v;
251             int w = sccvec[pre][i].w;
252             if(dis[son] > dis[pre] + w)
253             {
254                 dis[son] = dis[pre] + w;
255                 if(in[son] == 0)
256                 {
257                     Q.push(son);
258                     in[son] = 1;
259                 }
260             }
261         }
262     }
263 
264     return dis[e];
265 }
266 
267 void init()
268 {
269     step = cntEdge = top = 0;
270     scc = 1;
271     for(int i = 0; i < MAXN; i++)
272     {
273         sccvec[i].clear();
274         id[i] = 0;
275         inS[i] = 0;
276         dfn[i] = low[i] = -1;
277         head[i] = -1;
278     }
279 }
280 
281 void addEdge(int u, int v, int w)
282 {
283     edge[cntEdge].v = v;
284     edge[cntEdge].w = w;
285     edge[cntEdge].next = head[u];
286     head[u] = cntEdge++;
287 }
288 
289 void tarjan_scc(int n)
290 {
291     dfn[n] = low[n] = ++step;
292     myS[top++] = n;
293     inS[n] = 1;
294     for(int f = head[n]; f != -1; f = edge[f].next)
295     {
296         int son = edge[f].v;
297         if(dfn[son] == -1)
298         {
299             tarjan_scc(son);
300             low[n] = min(low[n], low[son]);
301         }
302         else if(inS[son] == 1)
303         {
304             low[n] = min(low[n], dfn[son]);
305         }
306     }
307     if(low[n] == dfn[n] && top != 0)
308     {
309         int tmp;
310         do
311         {
312             tmp = myS[--top];
313             inS[tmp] = 0;
314             id[tmp] = scc;
315         }while(top != 0 && tmp != n);
316         scc++;
317     }
318 }
319 
320 int main(void)
321 {
322 #ifndef ONLINE_JUDGE
323     freopen("in.txt", "r", stdin);
324 #endif
325     int n, m, cas_c = 0;
326     while(scanf("%d", &n), n)
327     {
328         scanf("%d", &m);
329         if(cas_c++ != 0)
330             printf("\n");
331         int u, v, w;
332         init();
333         for(int i = 0; i < m; i++)
334         {
335             scanf("%d %d %d", &u, &v, &w);
336             addEdge(u, v, w);
337         }
338         for(int i = 1; i <= n; i++)
339         {
340             if(dfn[i] == -1)
341                 tarjan_scc(i);
342         }
343 
344         deal_spfa(n);
345         int q;
346         scanf("%d", &q);
347         for(int i = 0; i < q; i++)
348         {
349             scanf("%d %d", &u, &v);
350             if(id[u] == id[v])
351                 printf("0\n");
352             else
353             {
354                 int ans = spfa(id[u], id[v]);
355                 if(ans == inf)
356                     printf("Nao e possivel entregar a carta\n");
357                 else
358                     printf("%d\n", ans);
359             }
360         }
361     }
362     return 0;
363 }
posted on 2012-08-16 08:36  cchun  阅读(507)  评论(0编辑  收藏  举报