BZOJ 1083 繁忙的都市

 拿到这个题第一反应想到了wikioi里的“舒适的路线”,便想到了最最暴力的解法:枚举每个点,从此点开始每次都做一遍最小生成树,然后按以下程序判断

    (1)是否连通 (2)边数是否小于当前记录的最小边数 (3)最大价值是否最小

于是便得到了下面的代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define INF (1<<30)
#define MAXN 310
#define MAXM 100000
using namespace std;
int f[MAXN];
int x[MAXM],y[MAXM],r[MAXM],w[MAXM];
int mem[MAXM];
int cmp(const int a,const int b){
    return w[a]<w[b];
}
int getf(int x){
    return f[x]==x ? x : f[x]=getf(f[x]);
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int u,v,c;
        scanf("%d%d%d",&u,&v,&c);
        x[i]=u;
        y[i]=v;
        w[i]=c;
        r[i]=i;
    }
    sort(r+1,r+m+1,cmp);
    int cntm=INF;
    int valm=INF;
    for(int j=1;j<m;j++){
        int cnt=0;
        int val=0;
        for(int i=1;i<=n;i++) f[i]=i;
        for(int i=1;i<=n;i++) mem[i]=1;
        bool flag=false;
        for(int i=j;i<=m;i++){
            int p=getf(x[r[i]]),q=getf(y[r[i]]);
            if(p!=q){
                f[p]=q;
                cnt++;
                val=max(w[r[i]],val);
                mem[q]+=mem[p];
                if(mem[q]==n){
                    flag=true;
                    break;
                }
            }   
        }
        if(flag) {
            if(cnt<cntm){
                cntm=cnt;
                valm=val;
            }
            if(cnt==cntm)
                valm=min(val,valm);
        }
    } 
    printf("%d %d",cntm,valm);
    return 0;
}

时间是费得长了点,幸而过了。

然后在网上搜题解,看到了“二分”这个神方法。基本思想是枚举答案,看在此答案下是否符合题意,就得到了如下代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define INF (1<<30)
#define MAXN 1010
#define MAXM 100000
using namespace std;
int f[MAXN];
int n,m;
struct node{
	int a,b,c;
}e[MAXM];
bool cmp(const node &h,const node &k){
	return h.c<k.c;
}
int getf(int x){
	return f[x]==x ? x : f[x]=getf(f[x]);
}
bool getans(int val){
	for(int i=1;i<=n;i++) f[i]=i;
	for(int i=1;i<=m;i++)
		if(val>=e[i].c){
			int p=getf(e[i].a),q=getf(e[i].b);
			if(p!=q) f[p]=q;
		}
	for(int i=2;i<=n;i++) if(getf(1)!=getf(i)) return false;
	return true;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].c);
	}
	sort(e+1,e+m+1,cmp);
	int left=1;
	int right=m;
	int ans;
	while(left<=right){
		int mid=(left+right) >> 1;
		if(getans(e[mid].c)){
			 right=mid-1;
			 ans=e[mid].c;
		}
		else left=mid+1;
	} 
	printf("%d %d\n",n-1,ans);
    return 0;
}




猜你喜欢

转载自blog.csdn.net/u011431896/article/details/34841405