|
Posted on 2007-05-28 23:41 oyjpart 閱讀(2364) 評論(3) 編輯 收藏 引用 所屬分類: ACM/ICPC或其他比賽
很久沒寫結題報告了 今天做Sightseeing trip 上來貼個 Ural:1004
Sightseeing trip Time Limit:1000MS Memory Limit:65536K Total Submit:317 Accepted:133 Special Judged
Description There is a travel agency in Adelton town on Zanzibar island. It has decided to offer its clients, besides many other attractions, sightseeing the town. To earn as much as possible from this attraction, the agency has accepted a shrewd decision: it is necessary to find the shortest route which begins and ends at the same place. Your task is to write a program which finds such a route.
In the town there are N crossing points numbered from 1 to N and M two-way roads numbered from 1 to M. Two crossing points can be connected by multiple roads, but no road connects a crossing point with itself. Each sightseeing route is a sequence of road numbers y_1, ..., y_k, k>2. The road y_i (1<=i<=k-1) connects crossing points x_i and x_{i+1}, the road y_k connects crossing points x_k and x_1. All the numbers x_1,...,x_k should be different.The length of the sightseeing route is the sum of the lengths of all roads on the sightseeing route, i.e. L(y_1)+L(y_2)+...+L(y_k) where L(y_i) is the length of the road y_i (1<=i<=k). Your program has to find such a sightseeing route, the length of which is minimal, or to specify that it is not possible,because there is no sightseeing route in the town.
Input The first line of input contains two positive integers: the number of crossing points N<=100 and the number of roads M<=10000. Each of the next M lines describes one road. It contains 3 positive integers: the number of its first crossing point, the number of the second one, and the length of the road (a positive integer less than 500).
Output There is only one line in output. It contains either a string 'No solution.' in case there isn't any sightseeing route, or it contains the numbers of all crossing points on the shortest sightseeing route in the order how to pass them (i.e. the numbers x_1 to x_k from our definition of a sightseeing route), separated by single spaces. If there are multiple sightseeing routes of the minimal length, you can output any one of them.
Sample Input
5 7
1 4 1
1 3 300
3 1 10
1 2 16
2 3 100
2 5 15
5 3 20
Sample Output
1 3 5 2
點數是100個 題目意思是找一個最小權圈 以任意序輸出 從圖論的角度上考慮 應該是任意選一條邊(枚舉) 然后刪除邊 再以一個點為原點求Dijkstra 找出最小權圈 o(M*N^2)的復雜度 一個更加好的算法是限定枚舉的點為圈內序號最大的點 這樣就避免了對一個圈的多次枚舉(參考程序3) 如果直接搜就是任選一個點開始走回到原點則記錄長度 搜的時候必須要先對每個點的邊按照邊權進行排序 以備后面大量剪枝
程序1
1 //Solution 2 //by oyjpArt 3 //Algorithm:Search 4 #include <vector> 5 #include <iostream> 6 #include <algorithm> 7 using namespace std; 8 9 const int N = 101; 10 struct Node {int x, w; void set(int xx, int ww) {x =xx; w = ww; }}; 11 vector<Node> adj[N]; 12 int nv, ne, ans[N], na, S, rec[N]; 13 bool chk[N]; 14 int best; 15 16 bool operator<(const Node& a, const Node& b) { 17 return a.w < b.w; 18 } 19 20 void search(int x, int sum, int depth, int father) { 21 int i; 22 if(x == S && chk[x]) { 23 if(sum < best) { 24 best = sum; na = depth; 25 for(i = 0; i < depth; i++) ans[i] = rec[i]; 26 } 27 return; 28 } 29 rec[depth] = x; 30 for(i = 0; i < adj[x].size(); ++i) if(adj[x][i].x != father) if(!chk[adj[x][i].x] || adj[x][i].x == S) { 31 chk[adj[x][i].x] = 1; 32 if(sum + adj[x][i].w < best) search(adj[x][i].x, sum + adj[x][i].w, depth+1, x); 33 chk[adj[x][i].x] = 0; 34 } 35 } 36 37 int main() { 38 scanf("%d %d", &nv, &ne); 39 int i, u, v, w; 40 Node now; 41 for(i = 0; i < ne; i++) { 42 scanf("%d %d %d", &u, &v, &w); 43 --u; --v; 44 now.set(v, w); 45 adj[u].push_back(now); 46 now.x = u; 47 adj[v].push_back(now); 48 } 49 for(i = 0; i < nv; ++i) 50 sort(adj[i].begin(), adj[i].end()); 51 52 best = 123456789; 53 for(i = 0; i < nv; ++i) { 54 memset(chk, 0, nv * sizeof(bool)); 55 S = i; 56 search(i, 0, 0, -1); 57 } 58 59 if(best == 123456789) { printf("No solution.\n"); return 0; } 60 printf("%d", ans[0]+1); 61 for(i = 1; i < na; ++i) printf(" %d", ans[i]+1); putchar('\n'); 62 63 return 0; 64 } 65 66
程序2
1 //Solution 2 //by oyjpArt 3 //Algorithm : Enumerate + Dijkstra 4 #include <stdio.h> 5 #include <string.h> 6 7 const int N = 101, M = 20001, MAXINT = 2000000000; 8 int ne, nv; 9 struct E { 10 int x, w; E* next; 11 void set(int xx, int ww, E* nn) {x = xx; w = ww; next = nn;} 12 }e[M], * head[N]; 13 int best, dist[N], q[N], ans[N], pre[N], na; 14 bool chk[N]; 15 16 void Dijk(int st, int end, int ow) { 17 memset(chk, 0, sizeof(chk)); 18 memset(dist, -1, sizeof(dist)); 19 int qe = 1, qs = 0, i; 20 E * p; 21 for(i = 0; i < nv; ++i) if(i != st) { 22 for(p = head[st]; p != NULL; p = p->next) { 23 if(p->x == i && p->w > 0 && (dist[i] == -1 || dist[i] > p->w ) ) 24 dist[i] = p->w; 25 } 26 if(dist[i] == -1) dist[i] = MAXINT; 27 } 28 q[0] = st; 29 dist[st] = 0; 30 chk[st] = 1; 31 for(i = 0; i < nv; ++i) pre[i] = st; 32 pre[st] = -1; 33 while(qs < qe) { 34 int cur = q[qs++]; 35 chk[cur] = 1; 36 if(ow + dist[cur] >= best) return; 37 if(cur == end) { 38 if(dist[end] + ow < best) { 39 na = 0; 40 for(i = cur; i != -1; i = pre[i]) ans[na++] = i; 41 best = dist[end] + ow; 42 } 43 return; 44 } 45 int _min = MAXINT, mini = -1; 46 for(i = 0; i < nv; i++) if(!chk[i]) { 47 if(dist[i] < _min) { 48 _min = dist[i]; 49 mini = i; 50 } 51 } 52 if(mini == -1) return; 53 q[qe++] = mini; 54 for(i = 0; i < nv; ++i) if(!chk[i]) { 55 for(p = head[mini]; p != NULL; p = p->next) if(p->x == i) break; 56 if(p == NULL) continue; 57 if(p->w > 0 && p->w + dist[mini] < dist[i]) { 58 dist[i] = p->w + dist[mini]; 59 pre[i] = mini; 60 } 61 } 62 } 63 } 64 65 int main() { 66 scanf("%d %d", &nv, &ne); 67 memset(head, NULL, nv * sizeof(E*)); 68 int i, u, v, w; 69 for(i = 0; i < ne; ++i) { 70 scanf("%d %d %d", &u, &v, &w); 71 --u; --v; 72 e[2*i].set(u, w, head[v]); 73 head[v] = &e[2*i]; 74 e[2*i+1].set(v, w, head[u]); 75 head[u] = &e[2*i+1]; 76 } 77 E * p, * q; 78 best = MAXINT; 79 for(i = 0; i < nv; ++i) { 80 for(p = head[i]; p != NULL; p = p->next) { 81 int w = p->w; 82 int j = p->x; 83 for(q = head[i]; q != NULL; q = q->next) if(q->x == j) q->w = -q->w; 84 for(q = head[j]; q != NULL; q = q->next) if(q->x == i) q->w = -q->w; 85 Dijk(i, j, w); 86 for(q = head[i]; q != NULL; q = q->next) if(q->x == j) q->w = -q->w; 87 for(q = head[j]; q != NULL; q = q->next) if(q->x == i) q->w = -q->w; 88 } 89 } 90 if(best == MAXINT) printf("No solution.\n"); 91 else { 92 printf("%d", ans[0] + 1); 93 for(i = 1; i < na; ++i) printf(" %d", ans[i] + 1); putchar('\n'); 94 } 95 return 0; 96 } 97 //唉 不用vector代碼量增大好多。。暈倒 98
程序3: 經wywcgs大牛提醒 改寫成了Floyd程序 時間銳減
1 #include <stdio.h> 2 #include <string.h> 3 4 const int N = 101; 5 const int MAXINT = 123456789; 6 int ne, nv; 7 int adj[N][N]; 8 int pre[N][N]; 9 int conn[N][N]; 10 int na, ans[N]; 11 int best; 12 13 void floyd() { 14 int i, j, k, tmp, p; 15 for(k = 0; k < nv; ++k) { 16 for(i = 0; i < k; ++i) { 17 for(j = 0; j < k; ++j) if(conn[i][k] && conn[k][j] && j != i) { 18 if( (tmp = adj[i][j] + conn[k][i] + conn[j][k]) < best) { 19 best = tmp; 20 na = 1; ans[0] = k; p = i; 21 while(p != -1) { 22 ans[na++] = p; 23 p = pre[p][j]; 24 } 25 } 26 } 27 } 28 for(i = 0; i < nv; ++i) 29 for(j = 0; j < nv; ++j) { 30 if(adj[i][j] > adj[i][k] + adj[k][j]) { 31 adj[i][j] = adj[i][k] + adj[k][j]; 32 pre[i][j] = pre[i][k]; 33 } 34 } 35 } 36 } 37 38 int main() { 39 int i, j, u, v, w; 40 memset(pre, -1, sizeof(pre)); 41 scanf("%d %d", &nv, &ne); 42 for(i = 0; i < nv; ++i) { 43 for(j = i+1; j < nv; ++j) 44 adj[i][j] = adj[j][i] = MAXINT; 45 adj[i][i] = 0; 46 } 47 for(i = 0; i < ne; ++i) { 48 scanf("%d %d %d", &u, &v, &w); 49 --u; --v; 50 if(w < adj[u][v]) 51 conn[u][v] = conn[v][u] = adj[u][v] = adj[v][u] = w; 52 pre[u][v] = v, pre[v][u] = u; 53 } 54 best = MAXINT; 55 floyd(); 56 if(best == MAXINT) printf("No solution.\n"); 57 else { 58 for(i = 0; i < na; ++i) { 59 printf("%d", ans[i] + 1); 60 if(i != na-1) putchar(' '); 61 else putchar('\n'); 62 } 63 } 64 65 return 0; 66 } 67
Feedback
# re: PKU1734 Sightseeing trip (CEOI99) 回復 更多評論
2007-05-30 22:08 by
呃……這道題有O(V^3)做法……一次floyd或者V次dijkstra…… 你可以再想想,總之不是很難……
# re: PKU1734 Sightseeing trip (CEOI99) 回復 更多評論
2007-07-28 17:27 by
大牛人啊!!
很經典的東西!!
謝謝了哈!
辛苦了!!
# re: PKU1734 Sightseeing trip (CEOI99) 回復 更多評論
2011-11-10 15:58 by
我感覺如果用搜索的話好像排序與不排序是一樣的吧,因為一個點是等可能的搜向鄰邊的,排序改變不了什么,就算先搜到最短的鄰邊,隨后還是有可能越走越遠
|