Timus 1569

https://acm.timus.ru/problem.aspx?space=1&num=1569

题意就是给你一个无向图,求最小直径生成树。

这题O(n3)的题解有很多,但是这题其实可以做到O(n3ω),其中ω是bitset中的,可能是3264

首先设最优的生成树是T。那么假设T的直径长度为偶数,也就是T的中心只有一个,那么我们可以在原图中枚举点,找到最远的两个点的距离和,就是直径的长度。

T的直径长度为奇数,那么将会出现两个相邻的中心,我们枚举这两个相邻的中心x,y。设离x最远的点的集合为Sx,离y最远的点的集合为Sy,那么iSxx的路径和iSyy的路径都必须经过边(x,y),否则我们只用一个中心就行了。

也就是,SxSy的交集必须是空。

此时我们用bitset维护点对的距离,离点i最远的点的集合Si,就可以做到O(n3ω)

代码:

#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl

const int maxn=2505;
int n,m,dist[maxn][maxn],pos[maxn][maxn];
std::bitset<2505> a[maxn],vis,cnt[maxn];

void bfs(int st,int *dis) {
	for(int i=1;i<=n;i++) vis[i]=1;
	std::queue<int> q;
	q.push(st); vis[st]=0;
	while(!q.empty()) {
		int pos=q.front(); q.pop();
		std::bitset<2505> nxt=a[pos]&vis;
		for(int i=nxt._Find_first();i!=nxt.size();i=nxt._Find_next(i)) {
			dis[i]=dis[pos]+1;
			q.push(i);
		}
		vis^=nxt;
	}
}

int I;
bool cmp(int i1,int i2) {
	return dist[I][i1]>dist[I][i2];
} 

int main() {
	scanf("%d%d",&n,&m);
	for(int i=1,x,y;i<=m;i++) {
		scanf("%d%d",&x,&y);
		a[x][y]=a[y][x]=1;
	}
	int ans=1000000000,ans1=-114514,ans2=-114514;
	for(int i=1;i<=n;i++) {
		bfs(i,dist[i]);
		for(int j=1;j<=n;j++) pos[i][j]=j;
		I=i;
		std::sort(pos[i]+1,pos[i]+n+1,cmp);
		for(int j=1;dist[i][pos[i][1]]==dist[i][pos[i][j]];j++) {
			cnt[i][pos[i][j]]=1;
		}
	//	ans=std::min(ans,dist[i][pos[i][1]]+dist[i][pos[i][2]]);
		if(ans>dist[i][pos[i][1]]+dist[i][pos[i][2]]) {
			ans=dist[i][pos[i][1]]+dist[i][pos[i][2]];
			ans1=i;
		}
	}
	std::vector<int> v;
	int mn=1000000000;
	for(int i=1;i<=n;i++) {
		if(dist[i][pos[i][1]]<mn) mn=dist[i][pos[i][1]],v.clear();
		if(dist[i][pos[i][1]]==mn) v.push_back(i);
	}
//	assert(v.size()<=2); debug(v.size()); debug(*v.begin());
	for(auto x : v) {
		for(auto y : v) {
			if(x==y||!a[x][y]) continue;
			if((cnt[x]&cnt[y]).any()) continue;
			ans1=x,ans2=y;
		}
	}
	std::queue<int> q;
	std::bitset<2505> vis;
	for(int i=1;i<=n;i++) vis[i]=1;
	q.push(ans1); vis[ans1]=0;
	if(ans2!=-114514) {
		printf("%d %d\n",ans1,ans2); 
		q.push(ans2); vis[ans2]=0;
	}
	while(!q.empty()) {
		int pos=q.front(); q.pop();
		std::bitset<2505> nxt=a[pos]&vis;
		for(int i=nxt._Find_first();i!=nxt.size();i=nxt._Find_next(i)) {
			printf("%d %d\n",pos,i);
			q.push(i);
		}
		vis^=nxt;
	}
	return 0;
}
posted @   Nastia  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示