一、定义
链式前向星本质上是用链表实现邻接表来存图。
二、创建
1 数组
使用数组时,需要4个变量:head,ver,Next,tot。其中,tot在初始化时要赋值为-1.
int head[100005],ver[100005],Next[100005],tot=-1;
1.1 add建图
void add(int x,int y){
ver[++tot]=y;
Next[tot]=head[x];
head[x]=tot;
}
若有权值,则增加edge数组。
void add(int x,int y,int z){
ver[++tot]=y;
edge[tot]=z;
Next[tot]=head[x];
head[x]=tot;
}
1.2 遍历
若遍历节点i,循环从 h e a d [ i ] head[i] head[i]开始,每次取Next。
for(int j=head[i];j!=-1;j=Next[j])
2 结构体
将变量用结构体封装起来即可。
3 vector(最简洁)
优点:空间可控,代码简短
3.1 建图
不带权:
vector<vector<int> >e(100);//定义
e[x].push_back(y);//加边
带权:
vector<vector<pair<int,int> > >e(100);//定义
e[x].push_back(make_pair(y,z));//加边
对,你没看错,结束了。
3.2 遍历(对于带权)
遍历节点i:
for(int j=e[i].size()-1;j>=0;j--){
cout<<i<<" "<<e[i][j].first<<" "<<e[i][j].second<<endl;
}
三、实践
1 模板链式前向星
题目描述
读入 n n n个点, m m m条边,以及 f l a g flag flag,若 f l a g = = 1 flag==1 flag==1,则图有向,否则无向。对每个点输出它的每一条边。
AC代码
#include<bits/stdc++.h>
#define ll long long
#define bug printf("---OK---")
#define pa printf("A: ")
#define pr printf("\n")
#define pi acos(-1.0)
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
vector<vector<pair<int,int> > >e(100);//定义
vector<vector<int> >e(100);
ll n,m,flag;
ll x,y,z;
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==0){
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;pr;
}
if(e[i].size()==0){
pr;
}
}
return 0;
}
2 树
题目描述
在这个问题中,给定一个值 S S S和一棵树。在树的每个节点有一个正整数,问有多少条路径的节点总和达到 S S S。路径中节点的深度必须是升序的。假设节点 1 1 1是根节点,根的深度是 0 0 0,它的儿子节点的深度为 1 1 1。路径不必一定从根节点开始。
AC代码
#include<bits/stdc++.h>
#define ll long long
#define bug printf("---OK---")
#define pa printf("A: ")
#define pr printf("\n")
#define pi acos(-1.0)
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const ll N=1e6+5;
ll n,s;
ll h[N],e[N],ne[N],idx=0;
ll a[N],sum[N],st[N];
void add(ll x,ll y){
e[idx]=y;ne[idx]=h[x];h[x]=idx++;
}
ll ans=0;
void dfs(ll u,ll fa){
sum[u]=sum[fa]+a[u];
st[sum[u]]++;
ans+=st[sum[u]-s];
for(int i=h[u];~i;i=ne[i]){
dfs(e[i],u);
}
st[sum[u]]--;
}
int main(){
memset(h,-1,sizeof h);
scanf("%d%lld",&n,&s);
for (ll i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
for (ll i=1;i<n;i++){
ll x,y;
scanf("%lld%lld",&x,&y);
add(x,y);
}
st[0]=1;
dfs(1,0);
printf("%lld",ans);
return 0;
}
3 Tree Cutting
题目描述
Farmer John的网络是树形的,连接着 N N N个牛棚。Bessie打算切断某一个牛棚的电源,使和这个牛棚相连的所有电缆全部中断。之后,就会存在若干子网络。为保证破坏够大,每一个子网的牛棚数不得超过总牛棚数的一半。
AC代码
/*
not only
树的重心
but also
DFS找儿子+枚举牛棚
*/
#include<bits/stdc++.h>
#define ll long long
#define bug printf("---OK---")
#define pa printf("A: ")
#define pr printf("\n")
#define pi acos(-1.0)
using namespace std;
ll n,size[10005];
vector<ll>e[10005],s[10005];
void dfs(ll u,ll fa){
size[u]=1;
for(int i=0;i<e[u].size();i++){
ll v=e[u][i];
if(v==fa){
continue;
}
dfs(v,u);
s[u].push_back(v);
size[u]+=size[v];
}
}
int main(){
cin>>n;
for(int i=1;i<n;i++){
ll x,y;
cin>>x>>y;
e[x].push_back(y);
e[y].push_back(x);
}
dfs(1,-1);
ll flag1=1;
for(ll i=1;i<=n;i++){
bool flag2=1;
for(ll j=0;j<s[i].size();j++){
ll u=s[i][j];
if(size[u]>n/2){
flag2=0;
break;
}
}
if(flag2&&size[i]>=n/2){
printf("%lld",i);pr;
flag1=0;
}
}
if(flag1){
printf("NONE");
}
return 0;
}