1.邻接矩阵的初始化:
头文件:
#include<cstring>
memset(G,0,sizeof(G));
2.插入边:
无向图:
G[u] [v]=G[v] [u]=1;
有向图:
G[u] [v]=1
3.邻接矩阵
G[h] [l];
memset(G,0,sizeof(G));
int m;
cin>>m;
for(int i=0;i<m;i++){
int a,b;
cin>>a>>b;
G[a] [b]=1;
}
4.邻接表
形成邻接表:
#include<bits/stdc++.h>
using namespace std;
int main(){
int max;
cin>>max;
vector<int> v;
vector<int> G[max];
int m;
cin>>m;
for(int i=0;i<m;i++){
int a,b;
cin>>a>>b;
G[a].push_back(b);
G[b].push_back(a);
}
for(int i=1;i<=10;i++){
cout<<i<<":";
for(int j=0;j<G[i].size();j++){
cout<<G[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
5.带权图
结构体定义:
struct Node{
int v; //记录连接点
int len; //记录边权
};
插入带权有向边:
vector<node> G[110];
void insert1(int u,int v,int w){
node tmp;
tmp.v=v;
tmp.len=w;
G[u].push_back(tmp);
}
插入无相边(=两条相反有向边)
void insert2(int u,int v,int w){
insert1(u,v,w);
insesrt1(v,u,w);
}
用邻接表表示带权图:
输入:
void input(){
int m;
cin>>m;
for(int i=0;i<m;i++){
int u,v,w;
cin>>u>>v>>w;
insert2(u,v,w);
}
}
输出:
void output(){
for(int i=0;i<=10;i++){
for(int j=0;j<G[i].size();j++){
cout<<"("<<i<<","<<G[i][j].v<<","<<G[i][j].w<<")"<<endl;
}
}
}
6.最小生成树
prim算法
#include<bits/stdc++.h>
using namespace std;
const int N=5010,M=2e5+10;
const int INF=0x3f3f3f3f;
int n,m,cnt,ans,a[N] [N],dis[M];
bool vis[N];
void prim(){
vis[1]=1;//从节点1开始
for(int i=1;i<n;i++){
int minn=INF;//查找当前最小点的边权
int pos;//并记录该节点的下标
for(int j=1;j<=n;j++){
if(!vis[j] && (minn==INF || dis[j]<minn)){
minn=dis[j];//记录最小点的边权
pos=j;
}
}
vis[pos]=1;
ans+=minn;//累加答案,因为该点已经为最小生成数的边权
++cnt;
if(minn==INF) break;
//提前break,说明此时cnt一定不超过n,以此判断能否生成
//此时minn=INF,说明没有比1e9更小的边权,但当前还在循环,即还有点未遍历是否未最小生成数的边权,产生矛盾
for(int j=1;j<=n;j++){
//更新当前最小生成树到其他点的最小距离
//即:如果这点没有被访问过,而且这个点到任意一点的距离比现在到树的距离近那么更近
if(!vis[j] && dis[j]>a[pos] [j]){
dis[j]=a[pos] [j];//更新边权,即就将更小值放入dis数组
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)初始化a,除了自己到自己的点为0,其余为边界值
for(int j=1;j<=n;j++)
if(i==j) a[i][j]=0;
else a[i][j]=INF;
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
a[x] [y]=a[y] [x]=min(a[x] [y],z);//避免重边
}
for(int i=1;i<=n;i++) dis[i]=a[1] [i];初始化距离数组,默认从顶点1开始计算,并把1能够到达的点放进dis数组
prim();
if(cnt>=n-1) printf("%d\n",ans);//能生成
else puts("orz");
return 0;
}
kruskal算法
#include<bits/stdc++.h>
using namespace std;
const int N=5100,M=2e5+50;
struct rec{
int x,y,z;
}edge[M];
int n,m,ans,cnt,fa[N];//cnt用来记录当前最小生成树的边的个数(避免改图不能生成树)
bool flag;//判断能否生成树
bool operator<(rec a,rec b){
return a.z<b.z;//按边权从小到大排序(因为是最小生成树)
}
int get(int x){
if(fa[x]==x) return x;
return fa[x]=get(fa[x]);//不懂的看并查集文章~~~~
}
void Kruskal(){
sort(edge+1,edge+1+m);
for(int i=1;i<=n;i++) fa[i]=i;//并查集初始化
for(int i=1;i<=m;i++){
//寻找一条连接x与y的边,由于之前预处理了(sort),所以取的一定为当前最小边权
int x_fa=get(edge[i].x);//查找x的祖先
int y_fa=get(edge[i].y);//查找y的祖先
if(x_fa==y_fa) continue;//若祖先一样说明已经属于同一集合,则跳过,即已经有可能成为最小生成树的一个
fa[x_fa]=y_fa;//把x的祖先标记为y的祖先,即合并两个集合
cnt++;//最小生成树的边的个树+1
ans+=edge[i].z;//累加答案
if(cnt==n-1) break;//若边数等于节点数-1说明,因为最小生成树边数等于点数-1
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].z);//由于需要对边权排序,所以用树组直接存图
}
Kruskal();//Kruskal求最小生成树的全值和
if(cnt==n-1) printf("%d",ans);//若存在最小生成数
else puts("orz");//不存在,输出orz
return 0;
}