ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Timus 1569

2022-09-08 23:30:59  阅读:206  来源: 互联网

标签:nxt dist vis int pos 1569 Find Timus


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

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

这题\(O(n^3)\)的题解有很多,但是这题其实可以做到\(O(\frac{n^3}{\omega})\),其中\(\omega\)是bitset中的,可能是\(32\)或\(64\)。

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

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

也就是,\(Sx\)和\(Sy\)的交集必须是空。

此时我们用bitset维护点对的距离,离点\(i\)最远的点的集合\(S_{i}\),就可以做到\(O(\frac{n^3}{\omega})\)。

代码:

#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;
}

标签:nxt,dist,vis,int,pos,1569,Find,Timus
来源: https://www.cnblogs.com/Nastia/p/16671215.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有