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