题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1196
可以说这是个瓶颈生成树的题?
不算很难的图论题,构思非常巧妙。。。
二分生成树的最大边权x,判断这样的生成树是否存在就行了。。。
每次判断时分成两步走,首先要限制c1小于等于x,判断生成树中的树边个数是否小于等于k,若大于k,表明这个生成树不存在。
再限制c2小于等于x,由于c2<c1,所以这时候c1不用管了,能加进去的边都加进去,加完边后判断生成树的树边是不是n-1(生成树联通了所有的点),若不是,表明这个生成树不存在。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#define MAXE 20050
#define MAXV 10050
using namespace std;
struct edge
{
int u,v,c1,c2;
}edges[MAXE];
int n,m,K;
int f[MAXV];
int findSet(int x)
{
if(f[x]==x) return x;
return f[x]=findSet(f[x]);
}
bool judge(int x) //设生成树最大的边权为x,判断这样的生成树是否存在
{
for(int i=1;i<=n;i++) f[i]=i;
int cnt=0; //当前生成树中树边总数
for(int i=1;i<=m;i++) //存在生成树中c1最大值小于等于x的限制,但是办不到,这样的生成树不存在
{
if(edges[i].c1>x) continue;
int rootu=findSet(edges[i].u),rootv=findSet(edges[i].v);
if(rootu!=rootv)
{
f[rootu]=rootv;
cnt++;
}
}
if(cnt<K) return false; //存在生成树中c1最大值小于等于x的限制,但是办不到,这样的生成树不存在
for(int i=1;i<=m;i++)
{
if(edges[i].c2>x) continue;
int rootu=findSet(edges[i].u),rootv=findSet(edges[i].v);
if(rootu!=rootv)
{
f[rootu]=rootv;
cnt++;
}
}
if(cnt<n-1) return false; //在之前的基础上加上生成树中c2最大值小于等于x的限制,但是办不到,这样的生成树不存在
return true;
}
int main()
{
scanf("%d%d%d",&n,&K,&m);
for(int i=1;i<m;i++)
scanf("%d%d%d%d",&edges[i].u,&edges[i].v,&edges[i].c1,&edges[i].c2);
int lowerBound=1,upperBound=30000,ans;
while(lowerBound<=upperBound)
{
int mid=(lowerBound+upperBound)/2;
if(judge(mid))
{
ans=mid;
upperBound=mid-1;
}
else lowerBound=mid+1;
}
printf("%d\n",ans);
return 0;
}