3
12
2015
0

【USACO】2395-Out of Hay

好久没写题解了……

题目描述:有N(1≤N≤2000)个节点,M(1≤M≤10000)条边。你要保留一些边,使得这个图连通且最大的边最小,输出最大边。

解题思路:→_→将边按权值从大到小排序,枚举从头开始删的边数~每次判一遍是否联通,感觉这样很对的说~,→_→理想中的最坏情况时间复杂度会到达O(NM)即遍历删几条边的复杂度*bfs复杂度,啊咧不会超啊→_→,不过我用的是更快的方法↓

解题思路2:二分答案+bfs,每次二分bfs判断图的联通性,于是时间复杂度就变成了 二分的复杂度*bfs的复杂度 ,所以总的复杂度是O(log(max(边权))M)。↓ 代码略丑

#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
int n,m;
bool b[2000+10];
int f[2001][2001][2];
#define max(a,b) (a>b?a:b)

inline int read(){
    char ch;int a=0;bool f=false;
    ch=getchar();while((ch<'0'||ch>'9')&&(ch!='-'))ch=getchar();
    if(ch!='-')a*=10,a+=ch-'0';else f=true;
    while(((ch=getchar())>='0')&&(ch<='9'))a*=10,a+=ch-'0';
    if(f)a=-a;
    return a;
}

bool find(int mid){
	queue<int>Q;
	int k=1;
	memset(b,0,sizeof(b));
	Q.push(1);b[1]=1;
	while(!Q.empty()){
		int x=Q.front();
		for(int i=1;i<=f[x][0][0];i++){
			if((!b[f[x][i][0]])&&(f[x][i][1]<=mid))
				b[f[x][i][0]]=1,Q.push(f[x][i][0]),k++;
		}
		Q.pop();
		if(k==n)return 1;
	}
	return 0;
}

int main(){
	n=read(),m=read();
	int Max=0;
	for(int i=1;i<=m;i++){
		int x,y,z;
		x=read(),y=read(),z=read();
		f[x][++f[x][0][0]][0]=y;
		f[x][f[x][0][0]][1]=z;
		f[y][++f[y][0][0]][0]=x;
		f[y][f[y][0][0]][1]=z;
		Max=max(z,Max);
	}
	int l=0,r=Max;
	while(l<r){
		int mid=(l+r)/2;
		if(find(mid))r=mid;
		else l=mid+1;
	}
	printf("%d",l);
}

loading...

Category: USACO | Tags: | Read Count: 325

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com