毛虫图(树的出度入度)

7 篇文章 0 订阅

#Caterpillar
An undirected graph is called a caterpillar if it is connected, has no cycles, and there is a path in the graph where every node is either on this path or a neighbor of a node on the path. This path is called the spine of the caterpillar and the spine may not be unique. You are simply going to check graphs to see if they are caterpillars.

For example, the left graph below is not a caterpillar, but the right graph is. One possible spine is
shown by dots.

Input
There will be multiple test cases. Each test case starts with a line containing n indicating the number of nodes, numbered 1 through n (a value of n = 0 indicates end-of-input). The next line will contain an integer e indicating the number of edges. Starting on the following line will be e pairs n1 n2 indicating an undirected edge between nodes n1 and n1. This information may span multiple lines. You may assume that n ≤ 100 and e ≤ 300. Do not assume that the graphs in the test cases are connected or acyclic.

Output
For each test case generate one line of output. This line should either be

Graph g is a caterpillar. 
1
or
Graph g is not a caterpillar.
as appropriate, where g is the number of the graph, starting at 1.

Sample Input

22
21
1 2 2 3 2 4 2 5 2 6 6 7 6 10 10 8 9 10 10 12 11 12 12 13 12 17
18 17 15 17 15 14 16 15 17 20 20 21 20 22 20 19
16
15
1 2 2 3 5 2 4 2 2 6 6 7 6 8 6 9 9 10 10 12 10 11 10 14 10 13 13 16 13 15
0

Sample Output

Graph 1 is not a caterpillar.
Graph 2 is a caterpillar.

题目链接
题目大体意思就是给你图,然后这个图要求要是一棵树,并且这棵树有一条主干,不在主干上的点必须以悬挂点的形式挂在主干上,不能挂在在主干的分支上,也就是在分支上不能出现小的分支。这个当时看了以后,先不说看不懂题意,问了队友题意之后还是一脸懵逼,这要怎么做?后来队友给我发了个题解的代码,一下子就被折服了,太强了。
题解的主要思想是:根据题目要求,我们的树不能出现多重分支。也就是说你如果把在这棵树挂在主干上的悬挂点全部都去掉的话,那么就只剩了一条主干,不可能存在其他分支。并且这个主干的两边一定原来连了许多悬挂边,后来成为了主干的两侧,也变成了悬挂边,这样我们记录一下有这样变化的点或者边,如果大于2就说明除了两侧,还有其他分支,是不符合题意的。用两个数组做记录,剩下的就是判断是不是一棵树了,用并查集就可以了。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;

struct node{
	ll y,next_s;
}side[601];

ll n,f[101],in[101],out[101],cnt,head[101];

void init(){
	memset(head,-1,sizeof(head));
	cnt=0;
}

ll find(ll x){
	ll r=x;
	while(r!=f[r]){
		r=f[r];
	}
	
	ll j=x;
	while(f[j]!=r){
		x=f[j];
		f[j]=r;
		j=x;
	}
	return r;
}
void add(ll x,ll y){
	side[cnt].y=y;
	side[cnt].next_s=head[x];
	head[x]=cnt++;
}

ll judge(){
	
	for(int i=1;i<=n;i++){
		if(in[i]==1){//悬挂点 
			for(int j=head[i];j!=-1;j=side[j].next_s){
				out[side[j].y]--;//将所有悬挂点链接的点的出度减一 
			}
		}
	}
	ll cn=0;
	//找 起初不是悬挂点,但删边之后称为悬挂点的数目
	//如果是毛虫图,cn肯定为2;
	//因为毛虫图删边之后只剩下了主干,最多两个头上的悬挂点 
	for(int i=1;i<=n;i++){
		if(in[i]>1&&out[i]==1){
			cn++;
		}
	}
	if(cn>2)
	return 0;
	else return 1;
}

int main(){
	ll e,cnt_s=1;
	while(~scanf("%lld",&n)&&n){
		init();
		scanf("%lld",&e);
		for(int i=0;i<=n;i++){
			f[i]=i;
			in[i]=0;
			out[i]=0;
		}
		ll sign=1;
		for(int i=0;i<e;i++){
			ll x,y;
			scanf("%lld %lld",&x,&y);
			add(x,y);add(y,x);
			in[x]++;in[y]++;out[x]++;out[y]++;//无向图入度出度都加一 
			ll tx=find(x);
			ll ty=find(y);
			if(tx!=ty)
			f[tx]=ty;
			else sign=0;//如果tx=ty,说明有环 
		}
		if(sign==0){//有环 
			printf("Graph %lld is not a caterpillar.\n",cnt_s++);
			continue;
		}
		ll cn=0;
		for(int i=1;i<=n;i++){
			if(f[i]==i){//检测有几个连通分支数 
				cn++;
			}
		}
		if(cn>1){//超过一个,不连通 
			printf("Graph %lld is not a caterpillar.\n",cnt_s++);
			continue;
		}
		if(!judge())
		printf("Graph %lld is not a caterpillar.\n",cnt_s++);
		else printf("Graph %lld is a caterpillar.\n",cnt_s++);	
	}
	return 0;
}

树的直径:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;

struct node{
	ll id;
	ll d;
	ll next_s;
}side[605];

ll n,head[101],flag[101],cnt,f[101],dis[101];

void init(){
	memset(head,-1,sizeof(head));
	cnt=0;
}

struct Node{
	ll id;
	ll d;
};
void add(ll x,ll y,ll d){
	side[cnt].d=d;
	side[cnt].id=y;
	side[cnt].next_s=head[x];
	head[x]=cnt++;
}

ll find(ll x){
	ll r=x;
	while(r!=f[r]){
		r=f[r];
	}
	ll j=x;
	while(f[j]!=r){
		x=f[j];
		f[j]=r;
		j=x;
	}
	return r;
}

ll bfs(ll x,ll num){
	for(int i=1;i<=n;i++){
		flag[i]=0;
		f[i]=i;
	}
	Node temp;
	temp.id=x;
	temp.d=0;
	queue<Node> p;
	p.push(temp);
	flag[x]=1;
	ll index=x;
	while(!p.empty()){
		temp=p.front();
		p.pop();
		for(int i=head[temp.id];i!=-1;i=side[i].next_s){
			if(!flag[side[i].id]){
				Node t;
				t.id=side[i].id;
				t.d=temp.d+side[i].d;
				if(num<t.d){
					index=side[i].id;
					num=t.d;
				}
				p.push(t);
				f[t.id]=temp.id;
				flag[side[i].id]=1;
			}
		}
	}
	return index;
}

int main(){
	ll e,cnt_s=1;
	while(cin>>n&&n){
		init();
		for(int i=1;i<=n;i++){
			f[i]=i;
		}
		cin>>e;
		ll cn=0,sign=0;
		for(int i=1;i<=e;i++){
			ll x,y;
			cin>>x>>y;
			add(x,y,1);
			add(y,x,1);
			ll tx=find(x);
			ll ty=find(y);
			if(tx!=ty){
				f[tx]=ty;
				cn++;	
			}
			else sign=1;
		}
		if(cn<n-1||sign==1){
			cout<<"Graph "<<cnt_s++<<" is not a caterpillar."<<endl;
			continue;
		}
		ll book=bfs(1,0);
		ll en=bfs(book,0);
		for(int i=1;i<=n;i++){
			flag[i]=0;
		}
		for(int i=en;f[i]!=i;i=f[i]){
			flag[i]=1;
			for(int j=head[i];j!=-1;j=side[j].next_s){
				flag[side[j].id]=1;
			}
		}
		ll cnt_k=0;
		for(int i=1;i<=n;i++){
			if(!flag[i]){
				cnt_k++;
			}
		}
		if(cnt_k>0){
			cout<<"Graph "<<cnt_s++<<" is not a caterpillar."<<endl;
		}
		else cout<<"Graph "<<cnt_s++<<" is a caterpillar."<<endl;
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
求解有向出度入度需要遍历整个,对于每个顶点,统计其出边和入边的数量即可。 以下是用C语言实现求解有向出度入度的示例代码: ```c #include <stdio.h> #define MAX_VERTEX_NUM 100 // 最多顶点数 int main() { int v[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 邻接矩阵 int inDegree[MAX_VERTEX_NUM] = {0}; // 入度数组 int outDegree[MAX_VERTEX_NUM] = {0}; // 出度数组 int vertexNum, edgeNum; // 顶点数和边数 // 读入顶点数和边数 printf("请输入顶点数和边数:"); scanf("%d%d", &vertexNum, &edgeNum); // 初始化邻接矩阵 for(int i = 0; i < vertexNum; i++) { for(int j = 0; j < vertexNum; j++) { v[i][j] = 0; } } // 读入边 printf("请输入每条边的起点和终点(顶点从0开始编号):\n"); for(int i = 0; i < edgeNum; i++) { int start, end; scanf("%d%d", &start, &end); v[start][end] = 1; // 标记邻接矩阵中对应位置为1 } // 统计入度出度 for(int i = 0; i < vertexNum; i++) { for(int j = 0; j < vertexNum; j++) { if(v[i][j] == 1) { // 有一条从i到j的边 outDegree[i]++; // i的出度+1 inDegree[j]++; // j的入度+1 } } } // 输出结果 printf("顶点 出度 入度\n"); for(int i = 0; i < vertexNum; i++) { printf("%d %d %d\n", i, outDegree[i], inDegree[i]); } return 0; } ``` 该代码实现了从标准输入中读入有向的顶点数和边数,再读入每条边的起点和终点,并使用邻接矩阵来表示有向。然后统计每个顶点的入度出度,并输出结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值