BZOJ 1050 旅行
Description
给你一个无向图,N(N<=500)个顶点, M(M<=5000)条边,每条边有一个权值Vi(Vi<30000)。给你两个顶点S和T,求一条路径,使得路径上最大边和最小边的比值最小。如果S和T之间没有路径,输出”IMPOSSIBLE”,否则输出这个比值,如果需要,表示成一个既约分数。 备注: 两个顶点之间可能有多条路径。
Input
第一行包含两个正整数,N和M。 下来的M行每行包含三个正整数:x,y和v。表示景点x到景点y之间有一条双向公路,车辆必须以速度v在该公路上行驶。 最后一行包含两个正整数s,t,表示想知道从景点s到景点t最大最小速度比最小的路径。s和t不可能相同。
Output
如果景点s到景点t没有路径,输出“IMPOSSIBLE”。否则输出一个数,表示最小的速度比。如果需要,输出一个既约分数。
Sample Input
【样例输入1】
4 2
1 2 1
3 4 2
1 4
【样例输入2】
3 3
1 2 10
1 2 5
2 3 8
1 3
【样例输入3】
3 2
1 2 2
2 3 4
1 3
4 2
1 2 1
3 4 2
1 4
【样例输入2】
3 3
1 2 10
1 2 5
2 3 8
1 3
【样例输入3】
3 2
1 2 2
2 3 4
1 3
Sample Output
【样例输出1】
IMPOSSIBLE
【样例输出2】
5/4
【样例输出3】
2
IMPOSSIBLE
【样例输出2】
5/4
【样例输出3】
2
HINT
【数据范围】
1< N < = 500
1 < = x, y < = N,0 < v < 30000,x ≠ y
0 < M < =5000
Source
自己YY了一个做法,感觉复杂度有点不太对,但跑起来还是飞快的。
枚举最大的边权,然后根据当前求出的最优答案找出最小边权,在这个范围内的边中做一遍最大生成树。先用并查集判断两点是否联通:不联通直接再见;否则再找出两点路径的最大值来更新答案。应该很好写,我都能想出来。
1 #include<cstring> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstdio> 5 #include<cstdlib> 6 using namespace std; 7 8 #define inf (1<<30) 9 #define maxn 510 10 #define maxm 5010 11 12 int n,m,up,down,side[maxn],toit[maxn*2],next[maxn*2]; 13 int s,t,tot,cnt,father[maxn],bac[maxm],arr[maxn],len[maxn*2]; 14 double ans = (double)inf; bool in[maxn]; 15 struct EDGE 16 { 17 int x,y,v; 18 friend inline bool operator <(const EDGE &a,const EDGE &b) { return a.v > b.v; } 19 }edge[maxm],temp[maxm]; 20 21 inline void init() { for (int i = 1;i <= n;++i) father[i] = i; } 22 23 inline int find(int a) { if (father[a]!=a) father[a] = find(father[a]); return father[a]; } 24 25 inline int gcd(int a,int b) { return b?gcd(b,a%b):a; } 26 27 inline void add(int a,int b,int c) 28 { 29 next[++cnt] = side[a]; side[a] = cnt; 30 toit[cnt] = b; len[cnt] = c; 31 } 32 33 inline void ins(int a,int b,int c) { add(a,b,c); add(b,a,c); } 34 35 inline int bfs() 36 { 37 int team[maxn],*head,*tail; 38 head = tail = team; memset(in,false,n+2); 39 *(++tail) = s; in[s] = true; arr[s] = inf; 40 while (head != tail) 41 { 42 int now = *(++head); 43 if (now == t) return arr[t]; 44 for (int i = side[now];i;i = next[i]) 45 if (!in[toit[i]]) *(++tail) = toit[i],arr[toit[i]] = min(arr[now],len[i]),in[toit[i]] = true; 46 } 47 } 48 49 inline void work(int key) 50 { 51 int lim = key/ans,all = 0,k = 0; 52 for (int i = 1;i <= m;++i) if (edge[i].v>lim&&edge[i].v <= key) temp[++all] = edge[i]; 53 init(); memset(side,0,4*(n+2)); cnt = 0; 54 sort(temp+1,temp+all+1); 55 for (int i = 1;i <= all;++i) 56 { 57 int r1 = find(temp[i].x),r2 = find(temp[i].y); 58 if (r1 != r2) 59 father[r1] = r2,ins(temp[i].x,temp[i].y,temp[i].v),++k; 60 if (k == n-1) break; 61 } 62 if (find(s) != find(t)) return; 63 lim = bfs(); 64 if ((1.0*key)/(1.0*lim) < ans) ans = (1.0*key)/(1.0*lim),up = key,down = lim; 65 } 66 67 int main() 68 { 69 freopen("1050.in","r",stdin); 70 freopen("1050.out","w",stdout); 71 scanf("%d %d",&n,&m); 72 init(); 73 for (int i = 1;i <= m;++i) 74 { 75 int a,b,c; scanf("%d %d %d",&a,&b,&c); 76 edge[i] = (EDGE){a,b,c}; 77 int r1 = find(a),r2 = find(b); 78 if (r1 != r2) father[r1] = r2; 79 bac[++tot] = c; 80 } 81 scanf("%d %d",&s,&t); 82 if (find(s) != find(t)) printf("IMPOSSIBLE\n"),exit(0); 83 sort(bac+1,bac+tot+1); tot = unique(bac+1,bac+tot+1)-bac-1; 84 for (int i = tot;i;--i) work(bac[i]); 85 int d = gcd(up,down); 86 up /= d; down /= d; 87 if (down != 1) printf("%d/%d",up,down); 88 else printf("%d",up); 89 fclose(stdin); fclose(stdout); 90 return 0; 91 }
高考结束,重新回归。