图论专栏

P1700

题面

\(n\) 个顶点,给出 \(n-1\) 条边,现在是要求是否存在一个点可以被所有点给指向,并且这个点的编号是最小的。

分析

思路1

反向建边,就变成了是否有一个点可以指向所有的点。

检测的这个部分可以用 dfs 或者 bfs 皆可。

思路2

由于 $n \le 100 $ ,所以直接暴力。

考虑每个点可以指向的所有边,然后看最小符合答案,即可暴力通过。

代码

思路2

#include<bits/stdc++.h>
using namespace std;
vector<vector<int>> g;
vector<int> f;
bool vis[105];
int n;
void dfs(int u){
	if(vis[u]) return;
	vis[u]=1;
	for(int i=0;i<g[u].size();i++){
		f[g[u][i]]++;
		dfs(g[u][i]);
	}
}
int main(){
	scanf("%d",&n);
	f.resize(n+1,0);
	g.resize(n+1);
	for(int i=1,u,v;i<n;i++){
		scanf("%d%d",&u,&v);
		g[u].push_back(v);
	}
	for(int i=1;i<=n;i++){
		memset(vis,0,sizeof(vis));
		dfs(i);
	}
	/*
	for(int i=1;i<=n;i++)
		printf("%d ",f[i]);
	printf("\n");
	*/
	for(int i=1;i<=n;i++){
		if(f[i]==n-1){
			printf("%d",i);
			return 0;
		}
	}
	printf("-1\n");
	return 0;
}

B3862

题面

\(n\) 个顶点和 \(m\) 条边构成的一个有向图。

输出 \(n\) 个数,第 \(i\) 个数表示编号为 \(i\) 的点能指向的最大编号的点的编号。

例如:

这种情况下,答案即为:

4 4 3 4

分析

一个点可以被某个点到达反过来说也可以到达可以到达这个点的点,那我们就可以反向建边。

处理完之后,在跑 n 次dfs找到访问过这个点的最大的点也就是答案存放在一个数组中。

最后输出这个数组。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
vector<int> g[N];
bool vis[N];
int a[N];
void dfs(int u,int i){
	if(vis[u])
		return;//如果已经被访问过就退出
	vis[u]=1,a[u]=i;//记录答案
	for(auto v: g[u])//找到所有可以访问当前这个点的点
		if(!vis[v]) dfs(v,i);
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1,u,v;i<=m;i++)
		scanf("%d%d",&u,&v),g[v].push_back(u);//反向建边
	for(int i=n;i>=1;i--)
		dfs(i,i);//处理答案
	for(int i=1;i<=n;i++)
		printf("%d ",a[i]);
	return 0;
}

P1330

题面

\(n\) 个点,\(m\) 条边。

需要做的就是至少删除多少个节点才能使得这个图不连通。

特别地,删除的两个节点在被删除之前不能相连。

分析

可以知道一条线段如果一个端点被选中另一个就不能选择,所以在DFS的时候可以加一个染色转换,由于数据比较大,所以只能用邻接表存。

然后我们不断搜索就可以了。

代码

```plaintext
#include<bits/stdc++.h>
using namespace std;
vector<int> g[10010];
int n,m,c[10010],x,f[10010];
void dfs(int k,int t){
	if(c[k]!=-1&&c[k]!=t){
		printf("Impossible");
		exit(0);
	}
	if(c[k]==t) return;
	c[k]=t;
	f[k]=1;
	x++;
	for(int i=0;i<g[k].size();i++) dfs(g[k][i],t^1);
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1,u,v;i<=m;i++){
		scanf("%d%d",&u,&v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
	int ans=0;
	memset(f,0,sizeof(f));
	for(int i=1;i<=n;i++)
		if(!f[i]){
			x=0;
			memset(c,-1,sizeof(c));
			dfs(i,0);
			int t=0;
			for(int i=1;i<=n;i++) t+=c[i]==1;
			ans+=min(t,x-t); 
		}
	printf("%d",ans);
	return 0;
}
posted @ 2025-04-24 21:10  Easoncalm  阅读(15)  评论(0)    收藏  举报