20200912 day7 图论复习(一)

1 图论基础

  1. 有向图\(G\)中,\(V\)表示顶点,\(E\)表示边。
  2. 无向图中不允许存在自环。
  3. 无向图中,定点的度是指关联于该顶点的边的数目。
  4. 有向图中,顶点的出度是离开该定点的边的数目。出度是指进入该顶点的边的数目。度是入度与出度之和。

1.1 邻接矩阵

\(|E|=n\)的邻接矩阵是一个$n \times n $的矩阵。无权图中用1表示邻接,0表示不邻接。
带权图中数字表示边的权重,无穷(有时用0)表示两点不邻接。
无向图的邻接矩阵是关于对角线对称的。

1.2 链式前向星

空间复杂度\(O(E)\)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 5005
#define M 20005
using namespace std;
int cnt=0,head[N]; 
struct node{
	int to,next,val;
}edge[N];
void add(int x,int y,int val1){
	edge[++cnt].next=head[x];
	edge[cnt].to=y;
	edge[cnt].val=val1;
	head[x]=cnt;
	
}
int main(){
	
}
memset(head,-1,sizeof(head));
for(int i=head[x];i!=-1;i=edge[i].next){
	int to1=edge[i].to;
	//do something
}

2 最小生成树

2.0 并查集

模板 LGP3367

题目描述

现在有一个并查集,你需要完成合并和查询操作。

输入格式

第一行包含两个整数\(N\)\(M\),表示共有\(N\)个元素和\(M\)个操作。
接下来\(M\)行,每行包含三个整数\(Z_i\)\(X_i\)\(Y_i\)
\(Z_i=1\)时,将\(X_i\)\(Y_i\)所在的集合合并
\(Z_i=2\)时,输出\(X_i\)\(Y_i\)是否在同一集合内,是的话输出\(Y\);否则话输出\(N\)

输出格式

如上,对于每一个\(Z_i=2\)的操作,都有一行输出,每行包含一个大写字母,为\(Y\)或者\(N\)

输入输出样例

输入

4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4

输出

N
Y
N
Y

数据规模

对于\(30\%\)的数据,\(N\leq 10\)\(M\leq 20\)
对于\(70\%\)的数据,\(N\leq 100\)\(M\leq 1000\)
对于\(100\%\)的数据,\(N\leq 10000\)\(M\leq 200000\)

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define N 50005
using namespace std;
//get together jihe
int fa[N];
int n; 
void init(){
	for(int i=1;i<=n;i++) fa[i]=i;
}
int find(int x){
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
void uni(int x,int y){
	fa[find(x)]=find(y);
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) fa[i]=i;
//init();
	while(m--){
		int a=0,b=0,c=0;
		scanf("%d%d%d",&a,&b,&c);
		if(a==1){
			fa[find(b)]=find(c);
		}
		else if(a==2){
			if(find(b)==find(c)){
				printf("Y\n");
			}
			else{
				printf("N\n");
			}
		}
	}
	return 0;
}

2.1 Kruskal

//Kraskul
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 5005
#define M 200005
using namespace std;
int cnt=0,head[M],fa[M];//fa维护点的连通性 
struct node{
	int to,next,val;
}edge[M];
int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
bool cmp(node x,node y){
	return x.val<y.val;
}
void add(int x,int y,int val1){
	edge[++cnt].next=head[x];
	edge[cnt].to=y;
	edge[cnt].val=val1;
	head[x]=cnt;
}
int tgn,tgto,ans;
int main(){
	memset(head,-1,sizeof(head));
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		fa[i]=i;
	} 
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&edge[i].next,&edge[i].to,&edge[i].val);
	}
	//kruskal
	sort(edge+1,edge+m+1,cmp);
	for(int i=1;i<=m;i++){
		tgn=find(edge[i].next);
		tgto=find(edge[i].to);
		if(tgn==tgto){
			continue;
		}
		//若已经联通,则不需要这一条边
		ans+=edge[i].val;
		 //边权记录答案
		fa[tgto]=tgn; //联通tgto和tgn 
		if(++cnt==n-1){
			break;
		}
		//边为点数减一时停止 
	}
	if(ans!=0) printf("%d",ans);
	else printf("orz");
	return 0;
}
/* 
for(int i=head[x];i!=-1;i=edge[i].next){
	int to1=edge[i].to;
	//do something
}
*/

2.2 Prim

复杂度\(O(V^2)\),适用于稠密图
prim详解

3 最短路

3.1 单源最短路径

(弱化版)

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define N  20005
#define edge e
using namespace std;
struct node{
	int to,next,val;
}e[1000001];
int head[N],num;
void add(int x,int y,int val1){
	e[++num].next=head[x];
	e[num].to=y;
	e[num].val=val1;
	head[x]=num;
}
bool vis[20005]={0};
long long dis[20005];
int n,m,s;
int a,b,c;
#define K 2147483647
int main(){
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<=n;i++) dis[i]=K;
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&a,&b,&c);
		add(a,b,c);
	}
	int curr=s;
	dis[s]=0;
	long long minn;
	while(!vis[curr]){
		vis[curr]=1;
		for(int i=head[curr];i!=0;i=edge[i].next){
			if(!vis[edge[i].to]&&dis[edge[i].to]>dis[curr]+edge[i].val){
				dis[edge[i].to]=dis[curr]+edge[i].val;//更新每个点 
			}
		}
		minn=K;
		for(int i=1;i<=n;i++){
			if(!vis[i]&&minn>dis[i]){
				minn=dis[i];
				curr=i;
			}
		}

	}
	for(int i=1;i<=n;i++) printf("%lld ",dis[i]);
	return 0;
} 
posted @ 2020-09-12 09:24  刘子闻  阅读(246)  评论(0编辑  收藏  举报