théorie et arbre graphique des sujets liés

théorie et arbre graphique des sujets liés

1. sommation des arbres.

Insérer ici l'image Description

Parce qu'il est un arbre, de tout point dans la recherche du nœud racine peut compléter la recherche de tous les côtés. Voici la racine de 1 recherche. Récursive sauver fois la contribution de chaque côté. Selon le nombre de contributions de petite à grande, et le poids du n-1
multiplication peut se résumer à 1. Un des points importants : le nombre de côtés de la contribution U-V = taille (V est le nombre de bords dans les noeuds de sous-arbre) * (N-size)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll n,ans[N],cnt;
vector<int>g[N];
ll dfs(int u,int fa){
	ll sz=1;
	for(auto v:g[u])
		if(v!=fa) sz+=dfs(v,u);
	ans[cnt++]=sz*(n-sz);
	return sz;
}
int main(){
	cin>>n;
	for(int i=1;i<n;i++){
		int u,v;
		cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1,0);
	sort(ans,ans+cnt);
	ll res=0;
	for(int i=n-1;i>0;i--) //res[0]是保存的以最后一个结点为起点的边的次数  显然没有为0 所以 i到1就够了 
		 res+=ans[n-i]*i;
		cout<<res<<endl;
	return 0;
} 

2. Le diamètre de l'arbre cherchent

Portail Sujet: POJ1985 titre de modèle
sur le code ci - dessous.

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
typedef long long ll;
#define mst(a) memset(a,0,sizeof a)
const int N=4e4+5;
struct edge{
	int to,nt,w;
}e[2*N];
int cnt,n,vis[N],h[N],d[N],m;//cnt记录边数,n顶点数,vis[i]标记结点i是否访问,h[i]头结点,d[i]保存到起点的最大距离 
void add(int u,int v,int w){
	e[cnt].to=v;
	e[cnt].w=w;
	e[cnt].nt=h[u];
	h[u]=cnt++;
}
void bfs(int u){
	mst(vis),mst(d);
	queue<int>q;
	q.push(u);
	while(q.size()){
		u=q.front();q.pop();vis[u]=1;
		for(int i=h[u];i;i=e[i].nt)
		{
			int v=e[i].to,w=e[i].w;
			if(!vis[v])
			{
				d[v]=d[u]+w;
				vis[v]=1;
				q.push(v);
			}
		}
	} 
}
int main(){
		ios::sync_with_stdio(false),cin.tie(0);
		cin>>n>>m; 
		cnt=1;//从1开始 
		mst(h);
		for(int i=1;i<=m;i++)
		{
			int u,v,w;
			char c;
			cin>>u>>v>>w>>c;
			add(u,v,w);
			add(v,u,w);
		}
		bfs(1);
		int mx=0,p;
		for(int i=1;i<=n;i++) ///这里是为了找到树的直径的一个端点B 
			if(d[i]>mx)
			{
				mx=d[i];
				p=i;// p为端点B 
			}
		bfs(p); //将端点B作为起点开始BFS 
		mx=0;
		for(int i=1;i<=n;i++){///找到另一个端点。 
			if(d[i]>mx)
			{
				mx=d[i];
				p=i; ///此时的端点A为直径的另一个端点。 
			}
		}
		cout<<mx<<endl;
	return 0;
} 

3. rechercher de multiples sources les plus longues d'arbres de route.

Sujet Portail: HDU2196

Idées: l'utilisation d' un diamètre d'arbre et BFS (ou DFS), où je trouve deux extrémités BFS à double diamètre. Ensuite , prendre une plus grande valeur pour chaque noeud.
Principe: l'extrémité du plus long chemin dans l'arbre un noeud doit être un point d'extrémité d'un diamètre d'arbre. Voici la preuve simple: Prenez tout point u, u est supposé que la fin du plus long chemin pour v,
case 1: si u du diamètre de l'arbre, le point d' extrémité diamètre v.
Cas n ° 2: Si u n'est pas diamétralement arbre, en contradiction, v on ne suppose pas que le diamètre de l'intersection d'extrémité, U ---- chemin le plus long du chemin v p ----- q est égal à c, étant donné que
d (u, c) + d (c, v)> d (u, c) + d ( c, p) de telle sorte que d (c, v)> d (c, p) de
telle sorte que d (c, v) + d (c, q)> d (c, p) + d ( c, q) = d (p , q) c.- à -d (v, q)> d (p, q) et D (p, q) la plus grande contradiction, de sorte que le diamètre du point d'extrémité doit être v.
le code ci - dessous.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mst(a) memset(a,0,sizeof a)
const int N=1e4+5;
struct edge{
	int to,nt,w;
}e[2*N];
int cnt,n,vis[N],h[N],d[N],pre[N];//cnt记录边数,n顶点数,vis[i]标记结点i是否访问,h[i]头结点,d[i]保存到起点的最大距离 
void add(int u,int v,int w){
	e[cnt].to=v;
	e[cnt].w=w;
	e[cnt].nt=h[u];
	h[u]=cnt++;
}
void bfs(int u){
	mst(vis),mst(d);
	queue<int>q;
	q.push(u);
	while(q.size()){
		u=q.front();q.pop();vis[u]=1;
		for(int i=h[u];i;i=e[i].nt)
		{
			int v=e[i].to,w=e[i].w;
			if(!vis[v])
			{
				d[v]=d[u]+w;
				vis[v]=1;
				q.push(v);
			}
		}
	} 
}
int main(){
	while(cin>>n){
		cnt=1;//从1开始 
		mst(h);
		for(int i=2;i<=n;i++)
		{
			int v,w;
			cin>>v>>w;
			add(i,v,w);
			add(v,i,w);
		}
		bfs(1);
		int mx=0,p;
		for(int i=1;i<=n;i++) ///这里是为了找到树的直径的一个端点B 
			if(d[i]>mx)
			{
				mx=d[i];
				p=i;// p为端点B 
			}
		bfs(p); //将端点B作为起点开始BFS 
		mx=0;
		for(int i=1;i<=n;i++){///找到另一个端点。 
			if(d[i]>mx)
			{
				mx=d[i];
				p=i; ///此时的端点A为直径的另一个端点。 
			}
		 pre[i]=d[i];  //pre[i]表示 结点i到 直径的一个端点B的最大距离 
		}
		bfs(p);//求每个结点到直径的端点A的最大距离。 
		for(int i=1;i<=n;i++)
			printf("%d\n",max(pre[i],d[i])); //此时的d[i]表示结点i到树直径的另一个端点A的最大距离 
	}   ///因为结点i的最大路径的终点肯定为树的直径的某一个端点。所以可以用max(pre[i],d[i]) 求 
	return 0;
} 

Cherchez coupe de l'arbre.

Sujet Portail: Titre de modèle POJ1144

Couper le point et de pointe.
Couper deux points théorèmes: Théorème 1 Si le nœud racine de l'arbre T s est le point de coupe, si et seulement si s et au- dessus , il y a deux nœuds enfants (ces parties seront divisés en plusieurs sous-arbres, aussi. assez en deux ou plusieurs composants connectés et, si un seul nœud enfant, le noeud est supprimé, il n'y aura que un sous-arbre, qui est un élément de communication, il est donc pas un point de coupe.
théorème 2 : Si le T non-arbre s racine est le point de coupe, s si et seulement s'il y a au moins un nœud enfant v et ses descendants ne sont pas roulé côté arrière peut être de retour relié aux s ancestrales (preuve du contraire: Si tous les nœuds enfants peuvent être annulées par le côté s liens vers le nœud racine, puis après avoir enlevé les restes de sous - arbre .S en communication avec l'arbre d' origine, mais un bloc de communication.
S'il y a un, le nœud enfant et ses descendants peut devenir un bloc de communication, il est divisé en . et deux ou plusieurs blocs de communication
procédé d'analyse de programmation: point de coupure: non-root: faible [v]> = num [u]
root: u == 1 && enfant> = 2
tranchant: faible [v]> NUM [u] (u, noeud enfant v elle-même seulement à v, u et u ne sont pas l'ancêtre à -dire u-v est que l'arête de coupe de bord.

codes.

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=105;
#define mst(a) memset(a,0,sizeof a) 
int low[N],num[N],dfn,n;//dfn记录递归顺序.
bool vis[N];//标记是否为割点
vector<int> g[N];
void dfs(int u,int fa){
	low[u]=num[u]=++dfn;//初始值
	//printf("u=%d,fa=%d\n",u,fa);
	int child=0;
	for(int i=0;i<g[u].size();i++)
	{
		int v=g[u][i];
		if(!num[v]) //若v没有访问过 
		{
			child++;
			dfs(v,u);
			low[u]=min(low[v],low[u]);//用后代的返回值更新父结点的low值 
			//printf("low[%d]=%d,low[%d]=%d\n",u,low[u],v,low[v]);
			if(low[v]>=num[u]&&u!=1)//如果不是根节点且存在一个子结点没有回退边到u的祖先 
				vis[u]=1;
		}
		else if(num[v]<num[u]&&v!=fa) //处理回退边 即v能连接到u的祖先&&v是u的子结点 
		low[u]=min(low[u],num[v]);//说明u及其后代能通过回退边到u的祖先,更新low[u]
	 }
	 if(u==1&&child>=2) //如果是根结点则要求子结点数大于等于2 
	 	vis[u]=1; 
}
int main(){
	int u,v,ans;
		while(cin>>n&&n){
			mst(vis),mst(low),mst(num),dfn=ans=0; //初始化 
			for(int i=1;i<=n;i++) g[i].clear(); //初始化 
			 while(cin>>u&&u)
			 {
			 		while((getchar())!='\n')
			 		{
			 			 cin>>v;
			 			 g[u].push_back(v);
			 			 g[v].push_back(u);
 					}
			 }
			 dfs(1,0);
			 for(int i=1;i<=n;i++) ans+=vis[i];
			 cout<<ans<<endl;
		}
		return 0; 
} 
Publié 18 articles originaux · a gagné les éloges 14 · vues 357

Je suppose que tu aimes

Origine blog.csdn.net/weixin_45750972/article/details/105024337
conseillé
Classement