欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

NWERC2020J-Joint Excavation【构造,贪心】

发布时间:2023/12/3 编程问答 41 豆豆
生活随笔 收集整理的这篇文章主要介绍了 NWERC2020J-Joint Excavation【构造,贪心】 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

正题

题目链接:https://codeforces.com/gym/103049/problem/J


题目大意

nnn个点mmm条边的一张无向图,选出一条路径后去掉路径上的点,然后将剩下的点分成点数相等的两份使得两份之间没有边连接。

1≤n,m≤2×1051\leq n,m\leq 2\times 10^51n,m2×105


解题思路

先跑出dfsdfsdfs树,这样就保证了所有的非树边都是返祖边。

发现如果我们选出树上一条根节点出发的路径那么其他子树之间一定是不连通的(因为要么子树之间有环,要么往上的环被删除)。

所以问题就变成了选出一条从根出发的路径然后把其他的分成大小相等的两份。

考虑贪心解决,我们走到一个点时可以把儿子的子树大小从小到大排列,然后两边那边不够就加给哪边,加剩最大的一个再继续往下分。

因为这样分的差一定不大于最大的那个,所以肯定是对的。


code

#include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int N=2e5+10; int n,m,siz[N],mark[N]; vector<int> G[N],T[N],p; void dfs(int x,int fa){siz[x]=1;for(int i=0;i<G[x].size();i++){int y=G[x][i];if(y==fa||siz[y])continue;T[x].push_back(y);dfs(y,x);siz[x]+=siz[y];}return; } bool cmp(int x,int y) {return siz[x]>siz[y];} void calc(int x,int fa,int a,int b){sort(T[x].begin(),T[x].end(),cmp);p.push_back(x);int lr=0;for(int i=0;i<T[x].size();i++){int y=T[x][i];if(y==fa)continue;if(!lr)lr=y;else if(a<=b)a+=siz[y],mark[y]=1;else b+=siz[y],mark[y]=2;}if(a<=b&&a+siz[lr]==b){mark[lr]=1;return;}if(a>=b&&b+siz[lr]==a){mark[lr]=2;return;}calc(lr,x,a,b);return; } void print(int x,int fa,int z){if(!mark[x])mark[x]=mark[fa];for(int i=0;i<T[x].size();i++)if(T[x][i]!=fa)print(T[x][i],x,z);if(mark[x]==z)printf("%d ",x);return; } int main() {scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);G[x].push_back(y);G[y].push_back(x);}dfs(1,0);calc(1,1,0,0);int w=(n-p.size())/2;printf("%d %d\n",p.size(),w);for(int i=0;i<p.size();i++)printf("%d ",p[i]);mark[0]=0;putchar('\n');print(1,0,1);putchar('\n');print(1,0,2);return 0; } 创作挑战赛新人创作奖励来咯,坚持创作打卡瓜分现金大奖

总结

以上是生活随笔为你收集整理的NWERC2020J-Joint Excavation【构造,贪心】的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。