IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 2021CCPC网络赛题解(目前只有10101011,待补充) -> 正文阅读

[数据结构与算法]2021CCPC网络赛题解(目前只有10101011,待补充)

1010 Bigraph Extension(思维,构造,并查集维护)

  • 题目描述: n 个左部点,n 个右部点。初始有 m 条边,都是左部点与右部点连接的边,且保证不存在顶点相同的边。求最少要添加多少条边,使得任意左部点,任意右部点,其最长简单路径的长度大于 n 。并输出最小字典序连连边 c 1 , d 1 , c 2 , d 2 c_1,d_1,c_2,d_2 c1?,d1?,c2?,d2? 。数据保证 n 为偶数。 T ∈ [ 1 , 1000 ] , n ∈ [ 2 , 2000 ] T\in[1,1000],n\in[2,2000] T[1,1000]n[2,2000]
  • 问题分析:
  • 结论: 结果一定是一个 2n 环。
  • 证明: 想要连边最小并且全部连通,显然是 2n-1 条边构成一棵树。但是对于一棵树,树上显然会存在最长简单路径为 1 的路径。不符合题意。考虑添加 2n 条边构成一个环。这样最长简单路径就是 n 了。但是由于 n 是偶数,左部点到右部点的路径不可能是偶数,因此最长简单路径一定是 n+1 ,符合题意。
  • 写法: m 条边不存在顶点相同的边,那么其实对正解没有任何影响。w我们拿两个指针 i,j 分别记录左右部点的最小度不为 2 的点即可。但是 i,j 不能直接连接的,还需要考虑 i,j 是否已经在一个并查集里,因为如果已经在一个并查集里,再连边的话:会提前构成环,就无法形成 2n 的大环了。因此需要找到一个度不为 2 的且与 i 不在一个并查集里的 j ,去连边。最后一次的时候再去找度为 1 的左右部点,连接,形成 2n 的大环。
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
int du1[N],du2[N],fa[N];

int find(int x){
	if(x==fa[x])return x;
	else return fa[x]=find(fa[x]);
}
int merge(int x,int y){
	int p1=find(x),p2=find(y);
	if(p1!=p2)fa[p1]=p2;
}
int main() {
	int T,n,m,u,v;
	cin>>T;
	while(T--) {
		cin>>n>>m;

		for(int i=1; i<=n; i++)du1[i]=du2[i]=0;
		for(int i=1;i<=2*n;i++)fa[i]=i;
		
		for(int i=1; i<=m; i++) {
			cin>>u>>v;
			du1[u]++;
			du2[v]++;
			merge(u,v+n);
		}
		cout<<2*n-m<<'\n';
		int i=1,j=1,num=m;
		while(1) {
			while(du1[i]==2)i++;
			while(du2[j]==2)j++;
			int temp=j;
			while(du2[temp]==2||(find(i)==find(temp+n)))temp++;
			du1[i]++;
			du2[temp]++;
			merge(i,temp+n);
			cout<<i<<" "<<temp<<'\n';
			num++;
			if(num==2*n-1)break;
		}
		for(int j=1;j<=n;j++){
			if(du2[j]==1){
				cout<<n<<" "<<j<<'\n';
				break;
			}
		}
	}
	return 0;
}

1011 Jumping Monkey(思维,并查集,差分建图)

  • 题目描述: 给定 n 个点的一棵树,树的样子已经给定。每个点都有权值 a i a_i ai? ,数据保证 a i a_i ai? 互不相同。点 u 能跳到点 v 的条件是: a v a_v av? 是 u 到 v 的这条简单路径上的点权最大值。求对于每个点 u ∈ [ 1 , n ] u\in[1,n] u[1,n],可以跳到多少个点(起点也算一个点)。 T ∈ [ 1 , 1 e 4 ] , n ∈ [ 1 , 1 e 5 ] , ∑ n ∈ [ 1 , 8 e 5 ] , a i ∈ [ 1 , 1 e 9 ] T\in[1,1e4],n\in[1,1e5],\sum n\in[1,8e5],a_i\in[1,1e9] T[1,1e4],n[1,1e5],n[1,8e5],ai?[1,1e9]
  • 问题分析: 正着思考很难想。考虑逐渐增加点 u ,求哪些点可以跳到点 u 从而使答案增加。显然逐渐增加点的顺序是点权从小到大。
  • 假设枚举到了 u ,考虑 u 的邻接点 v ,如果 a v < a u a_v<a_u av?<au? 则显然 v v v 所在的连通分量均可以走到 u ,从而使答案加 1 。然后将其再连接即可。这个过程我们可以用并查集维护。
  • 如何使整个连通分量的元素值均 + 1,考虑在 v 所属连通分量的根 r r r 挂一个差分标记,最后从根往下 dfs 即可(显然我们需要边用并查集维护,边构成一棵新树)。由于 u 要与 v 所属连通分量连接,但又要保证 u 的答案不会因为 r 的差分标记使得答案 + 1,可以将 u 作为 v 连通分量的新根,并建图 add(u,r) 即可。如下图
    在这里插入图片描述
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;

struct E{ 
	int u,v,next; 
}e[N*2];
int vex[N],d[N],tot,ans[N],fa[N],a[N];
vector<int>vec[N];

int find(int x){
	if(x==fa[x])return x;
	else return fa[x]=find(fa[x]); 
}
int add(int u,int v){
	tot++;
	e[tot].u=u;
	e[tot].v=v;
	e[tot].next=vex[u];
	vex[u]=tot;
}
void dfs(int u,int fa){
	ans[u]=d[u];
	ans[u]+=ans[fa];
	for(int i=vex[u];i;i=e[i].next){
		int v=e[i].v;
		if(v==fa)continue;
		dfs(v,u);
	}
}
struct node{
	int a,id;
}p[N];
int cmp(node x,node y){
	return x.a<y.a;
}


int main() {
	cin.tie(0);
	cout.tie(0);
	int T,n,u,v;
	cin>>T;
	while(T--){
		cin>>n;
		tot=0;
		for(int i=1;i<=n;i++){
		   vec[i].clear();
		   d[i]=vex[i]=ans[i]=0;
		   fa[i]=i;
		}
		for(int i=1;i<n;i++){
			cin>>u>>v;
			vec[u].push_back(v);
			vec[v].push_back(u); 
		}
		for(int i=1;i<=n;i++){
			cin>>a[i];
			p[i].id=i;
			p[i].a=a[i];
		}
		sort(p+1,p+n+1,cmp);
		for(int i=1;i<=n;i++){
			for(int j=0;j<vec[p[i].id].size();j++){
				int v=vec[p[i].id][j];
				if(a[v]>p[i].a)continue; 
				int x=find(v);
				d[x]++;
				add(x,p[i].id);
				add(p[i].id,x);
				fa[x]=p[i].id;
			}
		}
		int root=find(1);
		dfs(root,0);
		for(int i=1;i<=n;i++)cout<<ans[i]+1<<'\n'; 
	}
	return 0;
}

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-11 17:45:19  更:2021-10-11 17:46:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:53:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码