蓝桥杯 发现环 题型:图论

37 阅读2分钟

www.lanqiao.cn/problems/10…

邻接表写法

注意本题中为无向边,n虽然最大1e5,但是我们就要开2e5,不然过不去:

image.png

开2e5就可以过:

image.png

#include<bits/stdc++.h>
using namespace std;
int n;
const int N=1e5+10;
const int M=2*N;
int p[M];

int d[M],h[M],e[M],ne[M];
int cnt,idx;

void add(int a,int b)
{
   e[idx]=b;
   ne[idx]=h[a];
   h[a]=idx++;
}


int main()
{
	memset(h,-1,sizeof h);  //初始化头节点
	
  cin>>n;
  for(int i=0;i<n;i++)
  {
    int a,b;cin>>a>>b;
    add(a,b);add(b,a);
    d[a]++,d[b]++;  //无向边
  }
    queue<int> q;
    
	for (int i = 1; i <= n; i++) //找到所有只连一条边的点
	{
		if (d[i] == 1)
			q.push(i);
	}
	
    while(!q.empty())
    {
      int t=q.front();
      q.pop();

      for(int i=h[t];i!=-1;i=ne[i])
       {
         int j=e[i];  //x连的点y
         d[j]--;      //减去边 
         if(d[j]==1)q.push(j);  
       }
    }

  //环上的点至少有两条边,删去一条还有一条 
  for(int i=1;i<=n;i++)
  {
    if(d[i]>1)cout<<i<<" ";
  }
  return 0;
}#include<bits/stdc++.h>
using namespace std;
int n;
const int N=1e5+10;
const int M=2*N;
int p[M];

int d[M],h[M],e[M],ne[M];
int cnt,idx;

void add(int a,int b)
{
   e[idx]=b;
   ne[idx]=h[a];
   h[a]=idx++;
}


int main()
{
	memset(h,-1,sizeof h);  //初始化头节点
	
  cin>>n;
  for(int i=0;i<n;i++)
  {
    int a,b;cin>>a>>b;
    add(a,b);add(b,a);
    d[a]++,d[b]++;  //无向边
  }
    queue<int> q;
    
	for (int i = 1; i <= n; i++) //找到所有只连一条边的点
	{
		if (d[i] == 1)
			q.push(i);
	}
	
    while(!q.empty())
    {
      int t=q.front();
      q.pop();

      for(int i=h[t];i!=-1;i=ne[i])
       {
         int j=e[i];  //x连的点y
         d[j]--;      //减去边 
         if(d[j]==1)q.push(j);  
       }
    }

  //环上的点至少有两条边,删去一条还有一条 
  for(int i=1;i<=n;i++)
  {
    if(d[i]>1)cout<<i<<" ";
  }
  return 0;
}

结构体邻接表写法

#include <iostream>
#include <queue>
#include <stdio.h>

int p[200005];
int cnt;
struct edge {
	int y;
	int next;
};
int n;
struct edge e[200005];

int d[200005]; //记录某个点所连的边数 如果是有向图就记录点的入度

void add(int x,int y) //邻接表存图
{
	e[++cnt].next = p[x];
	e[cnt].y = y;
	p[x] = cnt;
}
int main()
{
	scanf("%d",&n);
	int a, b;
	for (int i = 0; i < n; i++)
		scanf("%d%d", &a, &b), add(a, b), add(b, a), d[a]++,d[b]++; //无向图

	std::queue<int> q;

	for (int i = 1; i <= n; i++) //找到所有只连一条边的点
	{
		if (d[i] == 1)
			q.push(i);
	}
	while (q.size())
	{
		int x = q.front();
		q.pop();
		for (int i = p[x]; i; i = e[i].next)
		{
			int j = e[i].y; //x连的点y
			d[j]--; //x-y这条边删掉
			if (d[j] == 1) //如果还有一条边,继续删除
				q.push(j);
		}
	}

	for (int i = 1; i <= n; i++) //如果还有点连的边数大于1,成环
		if(d[i] > 1)
		printf("%d ",i);

	return 0;
}