给定一张连通图,求所有生成树中最大边权与最小边权差最小的,输出它们的差值……
一 题目
原题链接
描述
求所有生成树中最大边权与最小边权差最小的,输出它们的差值。
输入
输入文件包含多组测试数据,每组测试数据如下: 第1行:2个整数n m (2 ≤ n ≤ 100 and 0 ≤ m ≤ n(n − 1)/2),n表示顶点数,m表示边数。接下来m行,每行3个空格分开的整数a b w(1 ≤ w ≤ 10000) , 表示顶点a与顶点b之间有一条边,权值为w。
输出
对每组测试数据,如果图存在生成树,输出生成树的差值最小的;否则,输出-1。
二 题解
$n$不大,考虑暴力。
把边权升序排序,每次固定mst的第一条边,那么最后一条边也肯定固定了。(贪心原理:最后一条边越靠前差值越少)。枚举起始边,kruskal求最小生成树,维护最优解就好了。
复杂度大约是$O(q(m^2 +mlogm))$。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| #include<iostream> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std;
int read(){ int s=0,ne=1; char c=getchar(); for(;c<'0'||c>'9';c=getchar()) if(c=='-') ne=-1; for(;c>='0'&&c<='9';c=getchar()) s=(s<<1)+(s<<3)+c-'0'; return s*ne; }
const int CP=110; const int CE=CP*CP;
const int INF=0x3f3f3f3f;
class fs{ public: int from,to,dist; void init(int f,int t,int d) {from=f; to=t; dist=d;} bool operator < (const fs& e)const {return dist<e.dist;} }E[CE]; int ecnt=0; void add(int x,int y,int z){ E[++ecnt].init(x,y,z); }
class ufs{ public: int fa[CP]; ufs() {for(int i=1;i<CP;i++) fa[i]=i;} void init() {for(int i=1;i<CP;i++) fa[i]=i;} int find(int u) {return fa[u]==u ? u : fa[u]=find(fa[u]);} bool exm(int x,int y) {return find(x)!=find(y);} void merge(int x,int y) {fa[find(x)]=find(y);} }s;
int n,m;
int mst() { sort(E+1,E+ecnt+1); int ans=INF; for(int st=1; st<=ecnt; st++) { s.init(); int cnt=0,lst=-1; for(int k=st; k<=ecnt&&cnt!=n-1; k++) { fs e=E[k]; if(!s.exm(e.from,e.to)) continue; s.merge(e.from,e.to); lst=k; cnt++; } if(cnt != n-1) continue; ans = min(ans, E[lst].dist-E[st].dist); } return ans==INF ? -1 : ans; }
int main() {
n=read(); m=read(); while(n) { ecnt = 0; while(m--) { int x=read(),y=read(),z=read(); add(x,y,z); } printf("%d\n",mst()); n=read(); m=read(); } return 0; }
|