usaco 2.4

题意

给几个联通图(>=2个),每个联通图的直径为图中任意两点最短距离的最大值,然后将任意2点(在不同的联通图中)用一个路径连起来(路径是有长度的),问连通后最小的这个直径是多少。刚开始是先用并查集合并一波,然后每个dfs一遍,找到离其最远的点(同一个联通图中)存如len中(len就是这个点与这个图的结点的最远距离),然后将距离连起来,枚举这个路径连接全部的点,找到连接后的最小值,这个值为这两个点的len+两个点的距离,然后其实是错误的,因为有可能这两个点的len+这两个点的距离还没有其图本身另外2个点的最远距离还远。搞了一整个上午+半个下午才搞定。

1、wa了好多发,刚开始是tle,本来以为数据范围小直接跑单源最短路即可,但是超时用了vector来优化。

2、wa是因为题意点没考虑全。!

/* 
ID: 13227851
PROG: cowtour
LANG: C++ 
*/  
#include <iostream>
#include <iomanip> 
#include <stdio.h>
#include <string.h>
#include <stack>
#include <map>
#include <vector>
#include <algorithm>
#include <set>
#include <queue>
#include <math.h>
using namespace std;
struct ttt{
	long double x,y;
};
ttt q1[180];
vector<int>gg[180];
long double map1[180][180];
int pre[180];
void init(){
	for(int i=1;i<=160;i++)
	pre[i]=i;
}
int find1(int x){  
    int r=x;  
    while(r!=pre[r]){  
        r=pre[r];  
    }  
    int i=x,j;  
    while(pre[i]!=r){  
        j=pre[i];  
        pre[i]=r;  
        i=j;  
    }  
    return r;  
}  
int find2(int x,int y){
	int x1=find1(x);
	int y1=find1(y);
	if(x1!=y1){
		pre[y1]=pre[x1];
	}
}
long double ggg[200];
long double dist[180];
long double len[180];
int fun(int x){
	int i,j;
	for(i=1;i<=160;i++)
	dist[i]=1e9+7;
	dist[x]=0;
	queue<int>qq;
	qq.push(x);
	long double max1=0;
	while(!qq.empty()){
		int u=qq.front();qq.pop();
		for(j=0;j<gg[u].size();j++){
			i=gg[u][j];
			if(map1[u][i]!=-1&&map1[u][i]+dist[u]<dist[i]){
				dist[i]=dist[u]+map1[u][i];
				qq.push(i);
			}
		}
	}
	for(i=1;i<=160;i++)
	if(dist[i]!=1e9+7)
	max1=max(max1,dist[i]);
	len[x]=max1;
	ggg[find1(x)]=max(ggg[find1(x)],max1);
}
char s1[2000];
long double map2[180][180];
long double dist2[200];
int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
	freopen("cowtour.in","r",stdin);
    freopen("cowtour.out","w",stdout);
    int i,j,f1,f2,f3,l1,t1,t2,t3,t4,l2,l3;
    int m,r;
   	int T,n;
   	memset(ggg,0,sizeof(ggg));
   	memset(q1,0,sizeof(q1));
   	memset(map1,-1,sizeof(map1));
   	memset(map2,0,sizeof(map2));
	memset(len,0,sizeof(len));
	cin >> n;
   	long double g1,g2,g3,g4;
   	init();
	   for(i=1;i<=n;i++){
   		cin >> q1[i].x >> q1[i].y;
	}
	char a,b;
	for(i=1;i<=n;i++){
		cin >> s1;
		for(j=0;j<n;j++){
			a=s1[j];
			if(i==j+1)continue;
			if(a=='1'){
				gg[i].push_back(j+1);
				gg[j+1].push_back(i);
				map1[i][j+1]=sqrt((q1[i].x-q1[j+1].x)*(q1[i].x-q1[j+1].x)+
				(q1[i].y-q1[j+1].y)*(q1[i].y-q1[j+1].y));
				map2[i][j+1]=map1[i][j+1];
				map2[j+1][i]=map1[i][j+1];
				map1[1+j][i]=map1[i][j+1];
				find2(i,j+1);
			//cout <<i << "   " << j+1 << "!~~! " << map2[i][j+1] << endl;
			}
		}
	}
	for(i=1;i<=n;i++)
	dist2[i]=0;
	//cout << map2[2][1] << endl;
	for(int k=1;k<=n;k++)
		for(i=1;i<=n;i++)
			for(j=1;j<=n;j++){
			if(i==1&&j==2&&k==3){
//		cout <<map2[1][3]<<"!!" << map2[1][2] << "  ~~~~  " << map2[2][3] << endl;
			}
				if(map2[i][j]!=0&&map2[j][k]!=0)
				if(map2[i][k]==0||map2[i][j]+map2[j][k]<map2[i][k]){
					map2[i][k]=map2[i][j]+map2[j][k];
					map2[k][i]=map2[i][k];
//	cout << i  << " ~~~   " << k << "   " << map2[i][k] << endl;
	}
}
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++){
			if(map2[i][j]!=0&&i!=j){
			dist2[i]=max(dist2[i],map2[i][j]);
	//	cout << i << " 到" << j << "的距离为" << map2[i][j] <<endl;
		}
	}
}
	//cout << map2[1][3] << "!!!!! "<< endl;
	for(i=1;i<=n;i++){
	fun(i);
//	cout << i << "的最大 " <<len[i] << "   " << dist2[i] << endl;
	}
	long double min1=1e9+7;
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++){
			if(i!=j&&find1(i)!=find1(j)){
				long double len1=sqrt((q1[i].x-q1[j].x)*(q1[i].x-q1[j].x)+
				(q1[i].y-q1[j].y)*(q1[i].y-q1[j].y));
				//if(min1>len1+dist2[i]+dist2[j]){
				//cout << "连接" << i << "到" << j << endl;
				long double len2=max(len1+len[i]+len[j],ggg[find1(i)]);
				len2=max(ggg[find1(j)],len2);
				min1=min(min1,len2);
				//}
			}
		}
		cout << setiosflags(ios::fixed) << setprecision(6) <<min1<< endl;
		//printf("%.6LLf\n",min1);
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值