【bzoj1050】 旅行comf
http://www.lydsy.com/JudgeOnline/problem.php?id=1050 (题目链接)
题意
给出一个无向图,求图中两点间某条路径使得最大权值除以最小权值的值最小
Solution
今天考试题,写了个萎的dijistra,30分。。。
正解是滑动窗口+最小生成树(其实并不是最小)。我们想让路径中最大的边和最小的边相差尽可能小,也就是说将边按权值从小到大排序后,路径就是序列中连续的一段所组成的生成树。枚举生成树中最小的边,然后往树中加边。当s与t联通时就break,更新答案。复杂度m²。
代码
// bzoj1050 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #include<queue> #define LL long long #define inf 2147483640 #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); using namespace std; inline LL getint() { int f,x=0;char ch=getchar(); while (ch<='0' || ch>'9') {if (ch=='-') f=-1;else f=1;ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();} return x*f; } const int maxn=5010; struct edge {int u,v,w;}e[maxn]; int fa[maxn],n,m,s,t; bool cmp(edge a,edge b) { return a.w<b.w; } int gcd(int x,int y) { return x%y==0?y:gcd(y,x%y); } int find(int x) { return x==fa[x] ? x : fa[x]=find(fa[x]); } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); sort(e+1,e+1+m,cmp); scanf("%d%d",&s,&t); int x1=-1,y1=-1; for (int i=1;i<=m;i++) { if (e[i].w==e[i-1].w) continue; //质的飞越,快的不只一点点 for (int j=1;j<=n;j++) fa[j]=j; for (int j=i;j<=m;j++) { int r1=find(e[j].u),r2=find(e[j].v); if (r1!=r2) fa[r1]=r2; if (find(s)==find(t)) { if (y1==-1 || (double)x1/y1>(double)e[j].w/e[i].w) x1=e[j].w,y1=e[i].w; break; } } if (y1==-1) {printf("IMPOSSIBLE");return 0;} } int x=gcd(x1,y1); x1/=x,y1/=x; if (y1==1) printf("%d\n",x1); else printf("%d/%d\n",x1,y1); return 0; }
This passage is made by MashiroSky.