Codeforce 1600Difficulty Graphs 20 questions

本文探讨了多个涉及图论和树形结构的算法问题,包括最短路径、连通性、颜色规划、树的构造、无环图分析等。通过Floyd、DFS、BFS等算法解决实际场景下的复杂问题,展示了这些概念在信息技术领域的广泛应用。
摘要由CSDN通过智能技术生成

1.CF601A The Two Routes

一个图有两种路,有这种路就没有那种路,求走两种路达到终点的时间

原图和补图跑Floyd判断联通即可

#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=405,inf=0x3f3f3f3f;
int dis1[maxn][maxn],dis2[maxn][maxn];
int main(){
	memset(dis1,inf,sizeof dis1);
	memset(dis2,inf,sizeof dis2);
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		dis1[x][y]=1;
		dis1[y][x]=1;
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(dis1[i][j]==inf){
				dis2[i][j]=dis2[j][i]=1;
			}
		}
	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				dis1[i][j]=min(dis1[i][j],dis1[i][k]+dis1[k][j]);
			}
		}
	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				dis2[i][j]=min(dis2[i][j],dis2[i][k]+dis2[k][j]);
			}
		}
	}
	
	if(dis1[1][n]==inf||dis2[1][n]==inf)printf("-1\n");
	else{
		printf("%d\n",max(dis1[1][n],dis2[1][n]));
	}
	return 0;
}

2.CF763A Timofey and a tree

选一个点,其左子树所有颜色必须相同,右子树所有颜色必须相同

根据题目要求可知,最多只能有三种情况,极限情况就是根,两颗子树分别为不同颜色

找一个点 其所连的所有边与其颜色不同的数量==所有连着两个不同颜色的边的数量,作为根节点,即可满足题目要求

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
unordered_set<int>st;
int col[maxn];
int ans[maxn],sum;
int a[maxn],b[maxn];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n-1;i++){
		int u,v;
		cin>>a[i]>>b[i];
	}
	for(int i=1;i<=n;i++){
		cin>>col[i];
	}
	for(int i=1;i<=n;i++){
		if(col[a[i]]!=col[b[i]]){
			sum++;
			ans[a[i]]++;
			ans[b[i]]++;
		}
	}
	for(int i=1;i<=n;i++){
		if(ans[i]==sum){
			printf("YES\n");
			printf("%d",i);
			return 0;
		}
	}
	printf("NO");
}

3.CF780C Andryusha and Colored Balloons

任意一个点与其距离为2以内的点颜色不能相同,求最少用的总颜色数量

直接dfs即可

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int col[maxn],f[maxn];
int vis[maxn];
int n,m,mm;
vector<int>e[maxn];
inline void add(int u,int v){
	e[u].push_back(v);
}
void dfs(int u,int fa){
	int now=0;
	for(auto v:e[u]){
		if(v==fa)continue;
		++now;
		while(now==col[u]||now==col[fa])now++;
		col[v]=now;
	}
	for(auto v:e[u]){
		if(v==fa)continue;
		dfs(v,u);
	}
}
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n-1;i++){
		int u,v;
		cin>>u>>v;
		add(u,v);
		add(v,u);
		vis[u]++;
		vis[v]++;
		mm=max({mm,vis[u],vis[v]});
	}
	col[1]=1;
	f[1]=1;
	dfs(1,1);
	cout<<mm+1<<endl;
	for(int i=1;i<=n;i++){
		printf("%d ",col[i]);
	}
	return 0;
}

4.CF246D Colorful Graph

选一种颜色,与其相连且颜色与其不同的点的颜色种类最小

因为要去重,所以用set保存即可,不同的数量相同的话输出点数最小的点

#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=1e5+5;
int col[maxn],ans[maxn];
set<int>st[maxn];
vector<int>e[maxn];
int mm;
int main(){
	cin>>n>>m;
	int nb=0x7f7f7f7f;
	for(int i=1;i<=n;i++){
		cin>>col[i];
		nb=min(nb,col[i]);
	}
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		if(col[x]!=col[y]){
			st[col[x]].insert(col[y]);
			st[col[y]].insert(col[x]);
		}
	}
	for(int i=1;i<=n;i++){
		if(st[col[i]].size()>st[nb].size()){
			nb=col[i];
		}
	}
	cout<<nb;
}

5.CF369C Valera and Elections

给一棵树,选一些点,修复其到根节点的所有路径,问最少要选多少个点

是一个很水的题,由于太菜wa了

标记子树(包括自己)权为1的点输出即可

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
typedef pair<int,int>pii;
vector<pii>e[maxn];
int size[maxn];
vector<int>jl;
int n,m;
void dfs(int u,int fa){
	int v,w;
	int now=size[u];
	for(auto x:e[u]){
		v=x.first;
		w=x.second;
		if(v==fa)continue;
		size[v]+=w-1;
		dfs(v,u);
		size[u]+=size[v];
	}
	if(now==1&&size[u]==1){
		jl.push_back(u);
	}
}
int main(){
	cin>>n;
	for(int i=1;i<n;i++){
		int u,v,w;
		cin>>u>>v>>w;
		e[u].push_back({v,w});
		e[v].push_back({u,w});
	}
	dfs(1,0);
	cout<<jl.size()<<endl;
	for(auto x:jl){
		printf("%d ",x);
	}
}

6.CF1006E Military Problem

u u u的子树 d f s dfs dfs序为 k k k的点

一个好题,一开始写了个暴力,一看 1 e 9 1e9 1e9的数据范围就想到肯定要把树的信息先预处理出来

可是基础太烂不知道怎么写

记录每个点的 d f n dfn dfn,记录第 t t t个遍历的到的是哪个点,如果子树 s i z e > = k size>=k size>=k的话输出 i d [ d f n [ u ] + k − 1 ] id[dfn[u]+k-1] id[dfn[u]+k1],否则输出 − 1 -1 1

#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=2e5+5;
vector<int>e[maxn];
int f[maxn],size[maxn];
int cnt,k;
int t;
int dfn[maxn];
int id[maxn];
void dfs(int u){
	dfn[u]=++t;
	id[t]=u;
	for(auto v:e[u]){
		dfs(v);
		size[u]+=size[v];
	}
}
int main(){
	int q;
	cin>>n>>q;
	size[1]=1;
	for(int i=2;i<=n;i++){
		int x;
		cin>>x;
		f[i]=x;
		size[i]=1;
		e[x].push_back(i);
	}
	dfs(1);
	while(q--){
		int u;
		cin>>u>>k;
		printf("%d\n",k<=size[u]?id[dfn[u]+k-1]:-1);
	}
	return 0;
}

7.CF659E New Reform

给一个无向图,求其边变为有向后最少有多少个点不能到达

一开始没有读懂真意,其实就是要找环,如果一个联通分量边数大于等于点数的话,一定会存在环,学到了一种用并查集判环的好方法

如果两个点不属于同一集合,合并,如果属于同一集合,标记该集合为有环的连通分量

输出无环的连通分量数量即可

#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=2e5+5;
int f[maxn],vis[maxn];
int find(int x){
	if(f[x]==x)return x;
	else return f[x]=find(f[x]);
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		f[i]=i;
	}
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		int fx=find(x);
		int fy=find(y);
		if(fx==fy){
			vis[x]=vis[y]=vis[fx]=vis[fy]=1;
		}
		else{
			f[fx]=fy;
			if(vis[x]||vis[y]||vis[fx]||vis[fy]){
				vis[x]=vis[y]=vis[fx]=vis[fy]=1;
			}
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		if(f[i]==i&&!vis[i])ans++;
	}
	cout<<ans;
}

8.CF639B Bear and Forgotten Tree 3

构造一棵n个点,深度h,最长链为d的树

先特判不成立的情况,如果直径>树高*2,必不可能成立

再如果直径和树高为1而节点数>2,必大于1,不成立

1.然后开始构造,先构造出刚好为树高的子树

2.再构造出另外一颗子树,让直径刚好满足

最后将所有的节点都连在1的叶子节点的父亲上即可

#include<bits/stdc++.h>
using namespace std;
int n,m,d,h;
const int maxn=2e5+5;
int main(){
	cin>>n>>d>>h;
	if(d>h*2||(h==d && d==1 && n>2)){
		printf("-1");
		return 0;
	}
	int i;
	for(i=1;i<=h;i++){
		printf("%d %d\n",i,i+1);
	}
	int j=1;
	for(i=h+2;i<=d+1;i++){
		printf("%d %d\n",j,i);
		j=i;
	}
	for(i=d+2;i<=n;i++){
		printf("%d %d\n",h,i);
	}
	return 0;
}

9.CF731C Socks

有n只袜子,k种颜色,在m天中,问最少修改几只袜子的颜色,可以使每天穿的袜子左右两只都同颜色

转化题意:求所有不想交集合中,各集合中,总袜子数 − - 与出现次数最多颜色不同颜色的袜子数

并查集+set去重,记录出现颜色出现次数之后要减掉,不能每次 m e m s e t memset memset v i s vis vis数组,会 T L E TLE TLE

#include<bits/stdc++.h>
using namespace std;
int n,m,tt,t,k;
const int maxn=2e5+5;
int col[maxn],f[maxn],vis[maxn];
int rr[maxn];
vector<int>e[maxn];
unordered_set<int>st;
int find(int x){
	if(f[x]==x)return x;
	return f[x]=find(f[x]);
}
int main(){
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++){
		f[i]=i;
	}
	for(int i=1;i<=n;i++){
		cin>>col[i];
	}
	int sum=0;
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		if(!rr[x])rr[x]=1,sum++;
		if(!rr[y])rr[y]=1,sum++;
		int fx=find(x);
		int fy=find(y);
		if(fx!=fy){
			f[fx]=fy;
		}
	}
	for(int i=1;i<=n;i++){
		e[find(i)].push_back(i);
		st.insert(find(i));
	}
	for(auto u:st){
		if(e[u].size()==1)continue;
		int ans=0;
		for(auto x:e[u]){
			vis[col[x]]++;
			ans=max(vis[col[x]],ans);
		}
		for(auto x:e[u]){
			vis[col[x]]--;
			ans=max(vis[col[x]],ans);
		}
		sum-=ans;
	}
	cout<<sum;
	return 0;
}

10.CF939D Love Rescue

题意:给定两个长度为n的由小写字母组成的字符串
每次可以花费1的代价,指定两个字母,把其中一个全部变为另一个
求使两个字符串相同的最小花费

exo me?

#include<bits/stdc++.h>
using namespace std;
int n,m,tt,t,k;
const int maxn=2e5+5;
int f[maxn],vis[maxn];
pair<char,char>e[maxn];
string s1,s2;
int find(int x){
	if(f[x]==x)return x;
	return f[x]=find(f[x]);
}
int main(){
	cin>>n;
	for(int i=0;i<maxn;i++){
		f[i]=i;
	}
	cin>>s1>>s2;
	int cnt=0;
	for(int i=0;i<n;i++){
		char ss1=s1[i];
		char ss2=s2[i];
		int f1=find(ss1);
		int f2=find(ss2);
		if(f1!=f2){
			f[f1]=f2;
			cnt++;
			e[cnt]={s1[i],s2[i]};
		}
	}
	cout<<cnt<<endl;
	for(int i=1;i<=cnt;i++){
		cout<<e[i].first<<" "<<e[i].second<<endl;
	}
	return 0;
}

11.CF1133F1 Spanning Tree with Maximum Degree

给出了一个由n个顶点和m条边组成的无向无权连通图。它保证在给定的图中没有自环或重边。

你的任务是找到这个图的一棵生成树,使得树上顶点的最大度数尽可能地大。回忆一下,顶点的度数是与之关联的边的数量

思路:找到度数最大的点dfs输出一遍图即可

#include<bits/stdc++.h>
using namespace std;
int n,m,ans;
constexpr int maxn=2e5+5;
int du[maxn],mm,nb,vis[maxn];
vector<int>e[maxn];
void dfs(int u){
	vis[u]++;
	for(auto v:e[u]){
		if(vis[v])continue;
		vis[v]++;
		printf("%d %d\n",u,v);
	}
	for(auto v:e[u]){
		if(vis[v]>1)continue;
		vis[v]++;
		dfs(v);
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);
		du[u]++;
		du[v]++;
		if(mm<du[u]){
			mm=du[u];
			nb=u;
		}
		if(mm<du[v]){
			mm=du[v];
			nb=v;
		}
	}
	dfs(nb);
	return 0;
}

12.CF986A Fair

每个点有自己的颜色,求每个点到s种不同颜色点的距离和

记录同一种颜色的所有点,对每一种颜色的点进行bfs,求得每种颜色到其他所有颜色的最小距离,排序后累加即可

#include<bits/stdc++.h>
using namespace std;
int n,m,k,s,ans;
constexpr int maxn=1e5+5;
int col[maxn];
int dis[maxn][105];
vector<int>e[maxn];
vector<int>jl[105];
int main(){
	cin>>n>>m>>k>>s;
	for(int i=1;i<=n;i++){
		cin>>col[i];
		jl[col[i]].push_back(i);
	}
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	memset(dis,-1,sizeof dis);
	for(int i=1;i<=k;i++){
		queue<int>q;
		for(auto v:jl[i]){
			q.push(v);
			dis[v][i]=0;
		}
		while(!q.empty()){
			int u=q.front();
			q.pop();
			for(auto v:e[u]){
				if(dis[v][i]==-1){
					dis[v][i]=dis[u][i]+1;
					q.push(v);
				}
			}
		}
	}
	for(int i=1;i<=n;i++){
		ans=0;
		sort(dis[i]+1,dis[i]+1+k);
		for(int j=1;j<=s;j++){
			ans+=dis[i][j];
		}
		printf("%d ",ans);
	}
	return 0;
}

13.CF131D Subway

给出一个 n个点,n 条边的无向无权图,图上每条边的长度为 1,保证图中有且仅由一个环。

你的任务是求出每一个点到环(环上任意一点)的最短路径长度

学到了一个新东西:基环树,就比普通的树多了一个环

用拓扑排序可以找到环上的所有点,再把环上的点作为起点进行spfa求出到其他所有点的最短距离即可

#include<bits/stdc++.h>
using namespace std;
int n,m,s,t;
constexpr int maxn=10005,inf=0x3f3f3f3f;
int ru[maxn];
int dis[maxn],inque[maxn];
vector<int>e[maxn];
inline void topo(){
	queue<int>q;
	for(int i=1;i<=n;i++){
		if(ru[i]==1)q.push(i);
	}
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(auto v:e[u]){
			if(ru[v]<=1)continue;
			ru[v]--;
			if(ru[v]==1)q.push(v);
		}
	}
}
inline void spfa(){
	queue<int>q;
	memset(dis,inf,sizeof dis);
	for(int i=1;i<=n;i++){
		if(ru[i]>=2)q.push(i),dis[i]=0,inque[i]=1;
	}
	while(!q.empty()){
		int u=q.front();
		q.pop();
		inque[u]=0;
		for(auto v:e[u]){
			if(ru[v]>=2)continue;
			if(dis[v]>dis[u]+1){
				dis[v]=dis[u]+1;
				if(!inque[v]){
					inque[v]=1;
					q.push(v);
				}
			}
		}
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		int u,v;
		cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);
		ru[u]++;
		ru[v]++;
	}
	topo();
	spfa();
	for(int i=1;i<=n;i++){
		cout<<dis[i]<<" ";
	}
	return 0;
}

14.CF954D Fight Against Traffic

求最多可以加上多少边,s到t的距离不会缩短

用Floyd求出所有点的距离后,枚举判断即可

初始化不能直接全部赋值为inf,因为要判断两点间是否有边

#include<bits/stdc++.h>
using namespace std;
int n,m,s,t;
constexpr int maxn=1005,inf=0x3f3f3f3f;
int dis[maxn][maxn];
int main(){
	cin>>n>>m>>s>>t;
//	memset(dis,inf,sizeof dis);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i!=j)dis[i][j]=inf;
		}
	}
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		dis[u][v]=1;
		dis[v][u]=1;
	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
			}
		}
	}
	int ans=0;
	for(int i=1;i<n;i++){
		for(int j=i+1;j<=n;j++){
			if(dis[i][j]!=1&&(min(dis[s][i]+dis[j][t],dis[s][j]+dis[i][t])+1>=dis[s][t])){
				ans++;
			}
		}
	}
	cout<<ans;
	return 0;
}

15.CF34D Road Map

给定一棵树,并给定一个根,现在要换一个根,求换根后每个点的父节点

输入:第一行 节点个数 原根 新根 第二行 除原根节点外每个节点的父节点

输出:除新根节点外每个节点的父节点

思路:直接dfs

#include<bits/stdc++.h>
using namespace std;
int n,m,s,t;
constexpr int maxn=1e5+5,inf=0x3f3f3f3f;
vector<int>e[maxn];
int f[maxn];
int r1,r2;
void dfs(int u,int fa){
	for(auto v:e[u]){
		if(v!=fa){
			f[v]=u;
			dfs(v,u);
		}
	}
}
int main(){
	cin>>n>>r1>>r2;
	for(int i=1;i<=n;i++){
		if(i==r1)continue;
		int x;
		cin>>x;
		e[i].push_back(x);
		e[x].push_back(i);
	}
	dfs(r2,0);
	for(int i=1;i<=n;i++){
		if(i==r2)continue;
		cout<<f[i]<<" ";
	}
}

16.咕了

17.咕了

18.咕了

19.咕了

20.咕了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值