C++ 链式前向星 笔记

链式前向星是一种存储图的数据结构,顾名思义,链式前向星使用链表的方式存储图的边、点、权。
利用数组实现,需要head[],nextt[],to[],idx。head用以记录节点的第一条边的编号,nextt用来存储下一条边的编号,to用来存储当前边的终点。
代码实现建图:

void add(int u,int v){
    to[++idx]=v;
    nextt[idx]=head[u];
    head[u]=idx;
}

若要加权就多定义一个存储权的数组:

void add(int u,int v,int c){
    to[++idx]=v;
    w[idx]=c;
    nextt[idx]=head[u];
    head[u]=idx;
}

图的遍历:

如果要遍历一个点所连的边,就从head开始,每次取nextt,直到为空

for(int i=head[k];i;i=nextt[i])

当然,链式前向星也可以使用结构体实现:


void add(int u,int v,int c){
    idx++;
    e[idx].to=v;
    e[idx].w=c;
    e[idx].next=head[u];
    head[u]=idx;
}

还有最方便的方法——vector
vector相对于那两种方法空间灵活,并且也不用麻烦地去手动维护链表

定义

vector<vector<int> > e(100);

加边

e[u].push_back(v);

带权

vector<vector<pair<int,int> > > e(100);

实战

1.模版题

输入n(点数),m(边数),flag(flag==1为有向,否则无向)
然后输入每条边的起点终点和权
输出每个点所连的边的终点和权

若flag为0,即无向图时,只需再反向建一次边就可以达到无向图的效果
最后遍历输出

#include<bits/stdc++.h>
using namespace std;
vector < vector < pair<int,int> > > e(2000005);
int n,m,x,y,z;
bool flag;
int main(){
    cin>>n>>m>>flag;
    for(int i=1;i<=m;i++){
        cin>>x>>y>>z;
        e[x].push_back(make_pair(y,z));
        if(!flag){
            e[y].push_back(make_pair(x,z));
        }
    }
    for(int i=1;i<=m;i++){
        for(int j=e[i].size()-1;j>=0;j--){
            cout<<i<<' '<<e[i][j].first<<' '<<e[i][j].second<<endl;
        }
        if(!e[i].size()){
            cout<<endl;
        }
    }
    return 0;
} 

2.树

此题给定一棵树和s,求多少条路径总和为s

使用DFS


#include<bits/stdc++.h>
using namespace std;
vector < vector < int > > e(100005);
int n,m,x,y,ans,z;
int a[100005],dep[100005];

void search(int k){
    if(dep[k]==m){
        ans++;
        return ;
    }
    for(int i=0;i<e[k].size();i++){
    	int xx=e[k][i];
    	dep[xx]=dep[k]+a[xx];
    	if(dep[xx]>m){
    		continue;
		}
		if(dep[xx]==m){
			ans++;
			continue;
		}
        search(xx);
    }
    
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	
	while(cin>>x>>y&&x!=EOF){
		z++;
		e[x].push_back( y );
	}
	for(int i=1;i<=n;i++){
		dep[1]=a[i];
		search(i);
	}
	cout<<ans;
	return 0;
} 

3.Tree Cutting

给定一棵 N N N 个节点的 无根树 。现在要找到所有的节点,使得删除这个节点之后,剩余的所有连通块中最大连通块的大小 < = <= <= N / 2 N/2 N/2

即树的重心
DFS 来找出每个节点的儿子,然后算出以每个节点为根的子树的大小,再枚举牛棚检查是否可以。


#include<bits/stdc++.h>
using namespace std;
vector < vector < int > > e(100005),b(100005);
int n,m,x,y,ans,z;
int sz[100005];
bool flag1,flag2;
void search(int u,int fa){
    sz[u]=1;
    for(int i=0;i<e[u].size();i++){
    	if(e[u][i]==fa){
    		continue;
		}
		search(e[u][i],u);
		b[u].push_back(e[u][i]);
		sz[u]+=sz[e[u][i]];
	}
}
int main(){
	cin>>n;
	for(int i=1;i<n;i++){
		cin>>x>>y;
		e[x].push_back( y );
		e[y].push_back( x );
	}
	search(1,-1);
	for(int i=1;i<=n;i++){
		flag2=0;
		for(int j=0;j<b[i].size();j++){
			z=b[i][j];
			if(sz[z]>n/2){
				flag2=1;
				break;
			}
		}
		if(sz[i]>=n/2&&!flag2){
			cout<<i<<endl;
			flag1=1;
		}
	}
	if(!flag1){
		cout<<"NONE";
	}
	return 0;
} 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值