其他分享
首页 > 其他分享> > Timus 1569

Timus 1569

作者:互联网

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