克鲁斯卡尔
利用并查集,将排好序的每条边,如果不存在于并查集中就依次插入
上模板,方便查阅
#include
#include
#include
using namespace std;
const int N = 2e5 + 10;
#define inf 0x3f3f3f3f
int fa[N];
int n, m;
struct edge
{
int u, v, w;
bool operator < (edge b) { return w < b.w; }
}edges[N];
int find(int x)
{
if (x == fa[x])
return x;
return fa[x] = find(fa[x]);
}
int kruskal()
{
int ans = 0, sum = 0;
sort(edges + 1, edges + 1 + m);
for (int i = 1; i <= m; i++)
{
int u = edges[i].u, v = edges[i].v, w = edges[i].w;
int fx = find(u), fy = find(v);
if (fx != fy)
{
fa[fx] = fy;
ans += w;
sum++;
}
if (sum == n - 1)return ans;
}
return -1;
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)//并查集初始化
fa[i] = i;
for (int i = 1; i <= m; i++)
{
int u, v, w;
scanf_s("%d%d%d", &u, &v, &w);
edges[i] = { u,v,w };
}
int ans = kruskal();
if (ans == -1)
cout << "impossible" << endl;
else
cout << ans << endl;
return 0;
}
普利姆
从开头不停寻找最短边,更新点集
#include
#include
#include
using namespace std;
#define inf 0x3f3f3f3f
#define N 505
int n,m;
int mp[N][N];
int dis[N],vis[N];
int prim()
{
memset(dis,inf,sizeof dis);
int ans=0;
memset(vis,0,sizeof vis);
dis[1]=0;
for(int k=0;k<n;k++)
{
int mint=inf,v;
for(int i=1;i<=n;i++)//寻找下一个最外部接口节点
{
if((mint>dis[i]) && !vis[i])
{
mint=dis[i];v=i;
}
}
if(mint==inf)
return inf;
vis[v]=1;
ans+=mint;
for(int i=1;i<=n;i++)//更新每个节点到外部接口节点的距离,为下次插点做准备
dis[i]=min(dis[i],mp[v][i]);
}
return ans;
}
int main()
{
cin>>n>>m;
memset(mp,inf,sizeof mp);
for(int i=0;i<m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
mp[a][b]=mp[b][a]=min(mp[a][b],c);
}
int ans=prim();
if(ans==inf)
cout<<"impossible"<<endl;
else
cout<<ans<<endl;
return 0;
}
最小生成树内进行dfs,以克鲁斯卡尔最小生成为例
dfs总结,拿题来说话吧 CF472D
传送门
题意:给一个n*n的邻接矩阵,要求判断原图是不是一棵树
首先拿到题,先做的就是一系列的特判,不满足直接NO
1、对角线必须都为0
2、非对角线必须非0
3、邻接矩阵必须按对角线对称
然后还可能会存在一些不满足的情况,比如样例里的1 1 1会出现环这些等等情况,可以使用最小生成树,用dfs表示出它的邻接数组,与所给数组对比,有偏差则就是NO,剩下便为YES,编码过程要用到dfs,理解了我好一段时间,很神奇的算法
上代码
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
const int N = 2005;
using namespace std;
int n;
int a[2005][2005];
int dis[2005][2005];
int fa[N];
int tot = 0;
struct bian
{
int x, y, z;
}b[2000010];
bool operator <(bian a, bian b)
{
return a.z < b.z;
}
struct edge
{
int to, next, v;
}e[10 * N]; int head[N];
int find(int x)
{
if (fa[x] != x)return fa[x] = find(fa[x]);
else return x;
}
int num = 0;
void ins(int u, int v, int w)
{
e[++num].to = v;
e[num].v = w;
e[num].next = head[u];
head[u] = num;
}
void insert(int u, int v, int w)
{
ins(u, v, w);
ins(v, u, w);
}
bool vis[N];
int top, zhan[N];
void kruskal()
{
for (int i = 1; i <= n; i++)
{
fa[i] = i;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (i < j)
{
b[++tot].x = i;
b[tot].y = j;
b[tot].z = a[i][j];
}
}
}
sort(b + 1, b + 1 + tot);
int cnt = 0;
for (int i = 1; i <= tot; i++)
{
int fx = find(b[i].x);
int fy = find(b[i].y);
if (fx == fy)continue;
else fa[fx] = fy;
cnt++;
insert(b[i].x, b[i].y, b[i].z);
if (cnt == n - 1)return;
}
}
void dfs(int cur)
{
for (int i = head[cur]; i; i = e[i].next)
{
if (vis[e[i].to])continue;
for (int j = 1; j <= top; j++)
{
dis[e[i].to][zhan[j]] = dis[zhan[j]][e[i].to] = dis[zhan[j]][cur] + e[i].v;
}
zhan[++top] = e[i].to;
vis[e[i].to] = 1;
dfs(e[i].to);
}
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
scanf("%d", &a[i][j]);
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (i == j)
{
if (a[i][j] != 0)
{
puts("NO");
return 0;
}
}
else
{
if (a[i][j] == 0)
{
puts("NO");
return 0;
}
}
}
}
int x = (n % 2 == 1 ? (n / 2 + 1) : (n / 2));
for (int i = 1; i <= x; i++)
{
for (int j = x + 1; j <= n; j++)
{
if (a[i][j] != a[j][i])
{
puts("NO");
return 0;
}
}
}
kruskal();
zhan[1] = 1;
top = 1;
vis[1] = 1;
dfs(1);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (dis[i][j] != a[i][j])
{
puts("NO");
return 0;
}
}
}
puts("YES");
}