BZOJ 1196 公路修建问题(二分+最小生成树)
题目要求求出图中的一颗生成树,使得最大的边权最小,且满足一级公路的个数>=k。
考虑二分最大边,问题就变为给出的图的生成树中,是否满足所有的边<=val,且一级公路的个数>=k。
所以我们把边按一级公路权值排序,优先选择能构成生成树的一级公路。这样贪心的构造。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-3 # define MOD 100000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; int Scan() { int res=0, flag=0; char ch; if((ch=getchar())=='-') flag=1; else if(ch>='0'&&ch<='9') res=ch-'0'; while((ch=getchar())>='0'&&ch<='9') res=res*10+(ch-'0'); return flag?-res:res; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=10005; //Code begin... struct Edge{int u, v, w1, w2;}edge[N<<1]; int n, m, k, fa[N]; int find(int x) { int s, temp; for (s=x; fa[s]>=0; s=fa[s]) ; while (s!=x) temp=fa[x], fa[x]=s, x=temp; return s; } void union_set(int x, int y) { int temp=fa[x]+fa[y]; if (fa[x]>fa[y]) fa[x]=y, fa[y]=temp; else fa[y]=x, fa[x]=temp; } bool check(int x) { int num=0; mem(fa,-1); FO(i,1,m) { int u=find(edge[i].u), v=find(edge[i].v); if (edge[i].w2>x||u==v) continue; if (edge[i].w1<=x) ++num; union_set(u,v); } return num>=k&&fa[find(1)]==-n; } bool comp(Edge a, Edge b){return a.w1<b.w1;} int main () { int u, v, w1, w2; n=Scan(); k=Scan(); m=Scan(); FO(i,1,m) edge[i].u=Scan(), edge[i].v=Scan(), edge[i].w1=Scan(), edge[i].w2=Scan(); sort(edge+1,edge+m,comp); int l=0, r=30001, mid; while (l<r) { mid=(l+r)>>1; if (check(mid)) r=mid; else l=mid+1; } printf("%d\n",r); return 0; }