图专题
并查集,寻找父节点,合并模板
/*
这题有个小坑,当然也不算是坑,就是,看起来是求并查集的没错,但是额外附加了一个条件,单个端点只接收一次消息,所以,不能有环出现,排除也很简单,根据树的边数为n-1定则,而且要所有端点必须为同一集合,那么M必须等于N-1,否则,
所有端点无法连通,或出现环,so~题目就简单啦~~
*/
#include
using namespace std;
//通信系统,要求所有结点都能收到发端消息且不重复
int father[1000];
int findFather(int a){
int x=a;
while(x!=father[x]){
x=father[x];
}
while(a!=father[a]){
int z=a;
a=father[a];
father[z]=x;
}
return x;
}
void init(int n){
for(int i=1;i<=n;i++){
father[i]=i;
}
}
void Union(int a,int b){
int A=findFather(a);
int B=findFather(b);
if(A!=B){
father[A]=B;
}
}
int main()
{
int n,k,a,b;
while(cin>>n>>k){
if(n==0) break;
init(n);
for(int i=0;i>a>>b;
Union(a,b);
}
int ans=0;
for(int i=1;i<=n;i++){
if(father[i]==i)
ans++;
}
//边只能有n-1条时才不会有环!!
if(ans==1&&k==n-1)
cout<<"Yes"<
图的遍历DFS邻接矩阵和邻接表法
//给定一个无向图和所有边,判断这个图是否所有顶点都是联通的
#include
#include
using namespace std;
const int maxn=1010;
bool G[maxn][maxn];
bool flag[maxn]={false};
int n;
//n是点数,m是边数
void DFS(int x){
flag[x]=true;
for(int i=1;i<=n;i++){
//由于是无向边true表示可达
if(flag[i]==false&&G[x][i]==true){
G[x][i]=false;
G[i][x]=false;
//上面这个操作是为了提前清除已经访问边,这样就可以 不用下一组初始化
DFS(i);
}
}
}
int main(){
int m,d1,d2;
while(cin>>n>>m){
if(n==0) break;
for(int i=0;i>d1>>d2;
if(G[d1][d2]==false)
G[d1][d2]=G[d2][d1]=true;
}
int number=0;
memset(flag,0,sizeof(flag));
for(int i=1;i<=n;i++){
if(flag[i]==false){
number++;
DFS(i);
}
}
if(number==1){
printf("YES\n");
}else{
printf("NO\n");
}
}
return 0;
}
//邻接矩阵法,其实就要最后的连通块只有一个,有点类似并查集!!
//邻接表法
#include
#include
#include
using namespace std;
const int maxn=1010;
vector Adj[maxn];
bool flag[maxn]={false};
int n;
void DFS(int x){
flag[x]=true;
for(int i=0;i>n>>m)
{
if(n==0)
break;
for(int i=0;i>d1>>d2;
Adj[d1].push_back(d2);
Adj[d2].push_back(d1);
}
int number=0;
memset(flag,0,sizeof(flag));
for(int i=1;i<=n;i++){
if(flag[i]==false){
number++;
DFS(i);
}
}
if(number==1) printf("YES\n");
else printf("NO\n");
}
return 0;
}
迪杰特斯拉求最短路径长度+从某点到另一点的路径
6 8 0
0 1 1
0 3 4
0 4 4
1 3 2
2 5 1
3 2 2
3 4 3
4 5 3
0 1 5 3 4 6
//迪杰特斯拉最短路劲
#include
#include
using namespace std;
const int MAXV=1000; //最大顶点数
const int INF=1000000000; //设置一个很大值表示不可达
int n,m,s,G[MAXV][MAXV]; //n为顶点数,m为边数,s为起点
int d[MAXV]; //起点到各点的最短路径长度
int pre[MAXV]; //prev【v】表示从起点到顶点v的最短路径上v的前一个顶点
bool vis[MAXV]={false}; //标记数组
void Dijkstra(int s){
fill(d,d+MAXV,INF); //s到所有点先设置成不可达
d[s]=0; //这个也很关键,s一开始到自己为0
for(int i=0;i>n>>m>>s;
//顶点个数,边数,起点编号
fill(G[0],G[0]+MAXV*MAXV,INF);
//对于矩阵如何初始化,学到了
for(int i=0;i>u>>v>>w;
G[u][v]=w;
//输入u,v以及u->v的边权,有向图
}
Dijkstra(s);
//直接算法入口
for(int i=0;i
优先队列实现地杰斯特拉
#include
#include
#include
using namespace std;
const int maxn=60;
const int INF=0x3fffffff;
int G[maxn][maxn],n,d[maxn];
bool vis[maxn]={false};
struct Node{
int v,dis;
//这是有点队列所需要的!!
bool operator<(const Node &a)const{
return dis>a.dis;
}
//结构定义
Node(int x,int y){
v=x;
dis=y;
}
};
void Dijkstra(int s){
fill(d,d+maxn,INF);
d[s]=0;
//使用优先队列查找未访问的距离最短结点
priority_queue q;
q.push(Node(s,d[s]));
for(int i=0;i>n){
cin>>s;
for(int i=0;i>G[i][j];
}
}
Dijkstra(s);
for(int i=0;i
prim最小生成树算法
#include
#include
#include
using namespace std;
const int maxn=110;
const int INF=0x3fffffff;
int G[maxn][maxn],d[maxn];
int n;
bool vis[maxn];
int prim()
{
fill(d,d+maxn,INF);
memset(vis,0,sizeof(vis));
d[1]=0;
int ans=0;
for(int i=0;i
并查集+最小生成树
#include
#include
using namespace std;
#define N 101
int Tree[N];
//关键算法,找到爸爸节结点的标号
int findRoot(int x){
//查找代表集合的树的根节点,分成两个集合,以此来判断是否要合并两点到一个集合
if(Tree[x]==-1){
return x;
}else{
//当Tree[x]=1时,表示x爸爸是1,Tree[1]=-1,return Tree[x]=1是一个整体!!
int tmp=findRoot(Tree[x]);
//找x的爸爸,递归
Tree[x]=tmp;
//tmp确实是x的爸爸,爸爸存了
return tmp;
}
}
struct Edge{
//边要有结构体,来进行排序
int a,b;//顶点编号
int cost;
//重载小于运算符很关键!!
bool operator < (const Edge &A) const{
return cost>n){
for(int i=1;i<=n*(n-1)/2;i++){
cin>>edge[i].a>>edge[i].b>>edge[i].cost;
}
sort(edge+1,edge+1+n*(n-1)/2);
for(int i=1;i<=n;i++){
Tree[i]=-1;
//初始所有边都处于孤立集合
}
int ans=0;
for(int i=1;i<=n*(n-1)/2;i++){
int a=findRoot(edge[i].a);
int b=findRoot(edge[i].b);
//查找两个顶点的集合信息
if(a!=b){
Tree[b]=a;
//合并两个集合,加入了一个边
cout<
克鲁斯卡尔最小生成树
6 10
0 1 4
0 4 1
0 5 2
1 2 1
1 5 3
2 3 6
2 5 5
3 4 5
3 5 4
4 5 3
11
//克鲁斯卡尔最小生成树算法
#include
#include <32/bits/stdc++.h>
using namespace std;
const int MAXV=110;
const int MAXE=10010;
struct edge{
int u,v; //边的两个端点编号
int cost; //边权
}E[MAXE];
bool cmp(edge a,edge b){
return a.cost"<>n>>m; //顶点数和边数
for(int i=0;i>E[i].u>>E[i].v>>E[i].cost;
}
int ans=kruskal(n,m);
cout << ans<< endl;
return 0;
}