标签:ast 并查集 速度 code 答案 cst cstring tput line
图论一直是小C的弱项,相比其它题型,图论的花样通常会更多一点,套路也更难捉摸。
3 3
1 2 10
1 2 5
2 3 8
1 3
5/4
1<N<=500,1<=x,y<=N,0<v<30000,0<M<=5000
看到最大和最小值我们就可以感觉到肯定不能直接走,然后很自然地想到了排序。
这种图论的题型常常要求我们逆向思考,我们不是找一条路径去更新答案,而是枚举一个答案看它能否构成路径。
于是我们枚举路径中的最小的那条边,从小到大加边,直到S和T连通,
说明存在一条S到T的路径。用最后加入的这条边和枚举的最小边更新答案。
判连通性用并查集即可。
时间复杂度O(m^2)
在黄学长博客里还看到一个比较妙的解法分享一下:
理论复杂度是一样的,但实际远小于上界。
#include <cstdio> #include <cstring> #include <algorithm> #define MN 505 #define MM 5005 #define INF 0x3FFFFFFF using namespace std; struct edge{int x,y,z;}b[MM]; int fa[MN]; int n,m,S,T,ans1,ans2,g; inline int read() { int n=0,f=1; char c=getchar(); while (c<‘0‘ || c>‘9‘) {if(c==‘-‘)f=-1; c=getchar();} while (c>=‘0‘ && c<=‘9‘) {n=n*10+c-‘0‘; c=getchar();} return n*f; } int getf(int x) {return fa[x]?fa[x]=getf(fa[x]):x;} inline void gather(int x,int y) {if (x!=y) fa[x]=y;} int gcd(int x,int y) {return y?gcd(y,x%y):x;} bool cmp(const edge& a,const edge& b) {return a.z<b.z;} int main() { register int i,j; n=read(); m=read(); for (i=1;i<=m;++i) b[i].x=read(),b[i].y=read(),b[i].z=read(); S=read(); T=read(); sort(b+1,b+m+1,cmp); ans1=INF; ans2=1; for (i=1;i<=m;++i) { memset(fa,0,sizeof(fa)); for (j=i;j<=m;++j) { gather(getf(b[j].x),getf(b[j].y)); if (getf(S)==getf(T)) break; } if (j>m) break; if ((double)b[j].z/b[i].z<(double)ans1/ans2) ans1=b[j].z,ans2=b[i].z; } if (i==1) return 0*printf("IMPOSSIBLE"); g=gcd(ans1,ans2); ans1/=g; ans2/=g; if (ans2==1) printf("%d",ans1); else printf("%d/%d",ans1,ans2); }
用并查集解决图论的问题也是常见的思路。
小C会告诉你迷之RE是因为并查集写错了?
标签:ast 并查集 速度 code 答案 cst cstring tput line
原文地址:http://www.cnblogs.com/ACMLCZH/p/7424407.html