您的位置:首页 > 其它

BJ 集训测试7 A模型

2018-03-21 15:53 218 查看
http://www.elijahqi.win/archives/2753

题目要求:加最少的边使得一棵树不存在割点

我们可以先考虑如果是割边的话应该怎么做。显然答案下界是 ⌈l/2⌉

⌈l/2⌉

其中 l

l

是树中的叶节点个数。我们可以构造出这样的方案:令叶节点的权值为 1 ,非叶节点的权值为 0 ,求整棵树的带权重心 c

c

。由于重心的每个儿子的子树里都只有不超过 ⌊c/2⌋

⌊c/2⌋

个叶子,我们不难构造出一组方案使得每条边连接的两个叶子都来自于重心的不同儿子的子树。

考虑割点,显然答案下界是 max(max{di−1},⌈l/2⌉)

max(max{di−1},⌈l/2⌉)

,其中 di

di

是点 i

i

的度数。我们可以构造出这样的方案:注意到之前的方案里除了重心之外,每个点都保证了删掉它后,它的所有儿子的子树依然是与重心所在的连通块连通的,固整个图也是连通的。

同样先求重心,每次如果最大子树未连的叶子节点大于1

1

我们就把其中一个叶子与最小子树的一个未连的叶子节点连起来,否则就依次连子树个数−1

−1

条边,可以证明这样连是最优的。

注意连边的时候当最大只为1的时候 不能采取大的和小的连边策略 因为这样的话重心可能被放过所以应该都取出来去临近的互相连

#include<set>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define pa pair<int,int>
#define N 550000
#define inf 0x3f3f3f3f
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
return x*f;
}
struct cmp{
inline bool operator()(const pa &a,const pa &b){return a.first>b.first||(a.first==b.first&&a.second<b.second);}
};
set<pa,cmp> s;int q
;
int n,size
,num,h
,root,f
;
vector<pa> ans;vector<int>son
;
struct node{
int y,next;
}data[N<<1];
inline void dfs(int x,int fa){
bool flag=0;size[x]=0;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if (y==fa) continue;flag=1;dfs(y,x);size[x]+=size[y];
}if (!flag) size[x]=1;
}
inline void get_root(int x,int fa){
f[x]=size[1]-size[x];
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if (y==fa) continue;
get_root(y,x);f[x]=max(f[x],size[y]);
}if (f[root]>f[x]) root=x;
}
inline void dfs1(int x,int fa,int id){
bool flag=0;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if (y==fa) continue;
flag=1;dfs1(y,x,id);
}if (!flag) son[id].push_back(x);
}
int main(){
//freopen("t1.in","r",stdin);
int T=read();
while(T--){
n=read();num=0;memset(h,0,sizeof(h));ans.clear();
for (int i=1;i<n;++i){
int x=read(),y=read();
data[++num].y=y;data[num].next=h[x];h[x]=num;
data[++num].y=x;data[num].next=h[y];h[y]=num;
}dfs(1,1);root=0;f[0]=inf;get_root(1,1);int cnt=0;
for (int i=h[root];i;i=data[i].next){
int y=data[i].y;son[++cnt].clear();dfs1(y,root,cnt);
}int last=0;
for (int i=1;i<=cnt;++i) s.insert(make_pair(son[i].size(),i));
while(!s.empty()){
if (s.begin()->first==1){
int tot=0;
while(!s.empty()) q[++tot]=s.begin()->second,s.erase(s.begin());
for (int i=1;i<tot;++i){
ans.push_back(make
4000
_pair(son[q[i]].back(),son[q[i+1]].back()));last=son[q[i]].back();
}if (tot==1) ans.push_back(make_pair(last,son[q[1]].back()));
break;
}
int id1=s.begin()->second;s.erase(s.begin());last=son[id1].back();
int id2=s.rbegin()->second;s.erase(--s.end());
ans.push_back(make_pair(son[id1].back(),son[id2].back()));
son[id1].pop_back();son[id2].pop_back();
if (son[id1].size())s.insert(make_pair(son[id1].size(),id1));
if (son[id2].size())s.insert(make_pair(son[id2].size(),id2));
}printf("%lld\n",ans.size());
for (int i=0;i<ans.size();++i) printf("%d %d\n",ans[i].first,ans[i].second);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: