您的位置:首页 > 其它

修公路 最小生成树 二分答案

2017-09-10 14:48 260 查看

NKOJ 3763 修公路

问题描述

某岛国有n个小岛构成(编号1到n),该国政府想要通过n-1条双向公路将这些小岛连接起来,使得任意两个岛屿之间都能相互到达。公路有两种,一种是高速公路,车速快,建设花费大;另一种是普通公路,车速慢,建设花费少。该国政府不想在一条公路上花费过多的钱,但又要求修建的公路中至少有k条高速公路。所以政府希望,在满足上述条件的情况下,使得最贵的一条公路花费尽可能少,请你帮忙计算出其中最贵一条公路的价格。

输入格式

第一行,三空格间隔的整数n,k,m,其中m表示有m对岛屿间可以修路。

接下来以下的m行,每行四个正整数a,b,c1,c2 表示在岛屿a与b 之间修高速公路花费c1块钱,修普通公路,花费c2块钱。

输出格式

一个整数表示最贵那条公路的费用。

数据范围

对于30%的数据, 1<=n<=1000 , 0<=k<=10 , n-1<=m<=3000

对于100%的数据,1<=n<=10000 , 0<=k<=n-1 , n-1<=m<=20000

(1≤a,b≤n,a≠b,1≤c2≤c1≤30000)

先给出正解:

从题目描述中得知最后得到的是一棵树。由题目中“最贵的公路花费尽可能”的描述,考虑二分答案,对于生成树的步骤采用与Kruskal算法相似的做法。

二分最贵的公路的花费。首先处理高速公路,如果找到满足条件的高速公路少于K条,那么当前答案小了;找到不少于K条的高速公路之后,讨论可选的普通公路能否补完一颗生成树即可。

时间复杂度 O(MlogMaxLen)。

#include<stdio.h>
#define MAXN 10005
#define MAXM 20005
int N,K,M;
struct node{int a,b,C1,C2;}edge[MAXM];

int fa[MAXN];
int gf(int x)
{
if(fa[x]!=x)fa[x]=gf(fa[x]);
return fa[x];
}

bool Kruskal(int ans)
{
int i,x,y,cnt=0;

for(i=1;i<=N;i++)fa[i]=i;

for(i=1;i<=M&&cnt<N-1;i++)
{
if(edge[i].C1>ans)continue;
x=edge[i].a;y=edge[i].b;
x=gf(x);y=gf(y);
if(x==y)continue;
fa[x]=y;
cnt++;
}//先选高速公路
if(cnt<K)return false;
for(i=1;i<=M&&cnt<N-1;i++)
{
if(edge[i].C2>ans)continue;
x=edge[i].a;y=edge[i].b;
x=gf(x);y=gf(y);
if(x==y)continue;
fa[x]=y;
cnt++;
}//再选普通公路
if(cnt==N-1)return true;
return false;
}

int main()
{
int i,L,R,mid;

scanf("%d%d%d",&N,&K,&M);
for(i=1;i<=M;i++)scanf("%d%d%d%d",&edge[i].a,&edge[i].b,&edge[i].C1,&edge[i].C2);

L=1;R=30000;
while(L<=R)
{
mid=L+R>>1;
if(Kruskal(mid))R=mid-1;
else L=mid+1;
}

printf("%d",L);
}


下面是一种贪心AC做法,但是正确性暂时不明

好像要利用到最小生成树的最长边一定是所有生成树最长边中最短的一个

具体实现是,先选出最小的满足要求的K条高速公路,然后在剩下的普通公路和高速公路中找出最小的N-K-1条构成生成树即可。生成树的最长边就是答案。

//不保证正确性,但是可以AC
#include<stdio.h>
#include<algorithm>
#define Max(x,y) ((x>y)?(x):(y))
#define MAXM 20005
#define MAXN 10005
using namespace std;
int N,K,M,Ans;
struct node{int a,b,len;}C1[MAXM],C2[MAXM];
bool operator<(node x,node y){return x.len<y.len;}

int fa[MAXN];
int gf(int x)
{
if(fa[x]!=x)fa[x]=gf(fa[x]);
return fa[x];
}

void Kruskal()
{
int i,j=1,x,y,fx,fy,cnt=0,z;

for(i=1;i<=M&&cnt<K;i++)
{
x=C1[i].a;y=C1[i].b;
fx=gf(x);fy=gf(y);
if(fx==fy)continue;
fa[fx]=fy;
cnt++;
Ans=Max(Ans,C1[i].len);
}

while(cnt<N-1)
{
if(i<=M&&C1[i].len<C2[j].len)
{
x=C1[i].a;y=C1[i].b;
z=C1[i].len;
i++;
}
else if(j<=M)
{
x=C2[j].a;y=C2[j].b;
z=C2[j].len;
j++;
}
fx=gf(x);fy=gf(y);
if(fx==fy)continue;
cnt++;
fa[fx]=fy;
Ans=Max(Ans,z);
}
}

int main()
{
int i,w,x,y,z;

scanf("%d%d%d",&N,&K,&M);
for(i=1;i<=M;i++)
{
scanf("%d%d%d%d",&w,&x,&y,&z);
C1[i].a=C2[i].a=w;
C1[i].b=C2[i].b=x;
C1[i].len=y;
C2[i].len=z;
}

for(i=1;i<=N;i++)fa[i]=i;
sort(C1,C1+M+1);
sort(C2,C2+M+1);

Kruskal();

printf("%d",Ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: