#include
#include
using namespace std;
const int N = 110;
int w[N][N];
int dist[N];
bool st[N];
int n;
int prime()
{
int res = 0;
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
//和dj一样 这里1号节点虽然是最短的,但是我们需要它去更新其他边,因此不能st[1] = true;
for (int i = 0; i < n; i ++ )//和dj一样,这里循环n次才能把n个节点加进最小生成树
{
int t = -1;
for (int j = 1; j <= n; j ++ )
if (!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
st[t] = true;
res += dist[t];
for (int j = 1; j <= n; j ++ )
{
dist[j] = min(dist[j], w[t][j]);//这里不用dist[t] + w[t][j],这是求一个点到一个集合的距离,后者是求点j到源点的距离
}
}
return res;
}
int main ()
{
cin >> n;
for (int i = 1; i <= n; i ++ )//题目要的答案和节点的下标无关,这里能把它存下来就行了
for (int j = 1; j <= n; j ++ )
cin >> w[i][j];
cout << prime();
return 0;
}
#include
#include
#include
using namespace std;
const int N = 110, M = 210;
struct Edge
{
int a, b, w;
bool operator < (const Edge &t)const
{
return w < t.w;
}
}e[M];
int p[N];//并查集父类数组
int n, m;
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];//return x 也是一样的
}
int main ()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++ ) p[i] = i;//并查集初始化(这个经常忘),这个下标i是有意义的,要根据题目给的节点编号来
for (int i = 0; i < m; i ++ )
{
int a, b, w;
cin >> a >> b >> w;
//e[i].a = a, e[i].b = b, e[i].w = w;
e[i] = {a, b, w};
}
sort(e, e + m);
int res = 0;
for (int i = 0; i < m; i ++ )
{
int a = find(e[i].a), b = find(e[i].b), w = e[i].w;//后面不用再find了,因为我们a,b在定义的时候就是他们所属的集合
if(a != b) p[a] = b;
else res += w;
}
cout << res;
return 0;
}
和上题一摸一样,但是题意要求的out看起来需要特别处理,其实只要想清楚kruskal的性质就好
//kruskal本身就具有选择的路的权值中最大的权值尽量小这个性质,因为我们边是排序了的
#include
#include
using namespace std;
const int N = 310, M = 8010;
struct Edge
{
int a, b, w;
bool operator < (struct Edge &t)
{
return w < t.w;
}
}e[M];
int n, m;
int p[N];
int find (int x)
{
if (p[x] != x) p[x] = find (p[x]);
return p[x];
}
int main ()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++ ) p[i] = i;
for (int i = 0; i < m; i ++ )
{
int a, b, w;
cin >> a >> b >> w;
e[i] = {a, b, w};
}
sort(e, e + m);
int cnt = 0, res = 0;
for (int i = 0; i < m; i ++ )
{
int a = find(e[i].a), b = find(e[i].b), w = e[i].w;
if (a != b)
{
p[a] = b;
cnt ++ ;
res = w;
}
}
cout << cnt << " " << res ;
return 0;
}
//1.用到了缩点,但本题的是无形中的,一个联通块的缩成了它的父节点
//2.知道了kurskal有多牛,可以解决已经有一些边的最小生成树问题,也可以解决只找一部分边的最小生成树的问题
#include
#include
#include
using namespace std;
const int N = 2010, M = 10010;
struct Edge
{
int a, b, w;
bool operator < (struct Edge & t)
{
return w < t.w;
}
}e[M];
int p[N];
int n, m;
int find (int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main ()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++ ) p[i] = i;
int res = 0, k = 0;
for (int i = 0; i < m; i ++ )
{
int t, a, b, w;
cin >> t >> a >> b >> w;
if (t == 1)
{
p[find(a)] = find(b);//先建立必须要选择的边
res += w;
}
else
{
e[k ++ ] = {a, b, w};//不是必须要选择的再加入e数组
}
}
sort(e, e + k);
for (int i = 0; i < k; i ++ )
{
int a = find(e[i].a), b = find(e[i].b), w = e[i].w;
if (a != b)
{
p[a] = b;
res += w;
}
}
cout << res;
return 0;
}
题意就是求最小生成树,因为边权都是正数,那么我们多选一条边必然会导致我们的代价增大
但如果题目说了边权为正或者负数,那么就不是最小生成树了,极端一点所有边都是负的,那么我们为了代价最小肯定是所有边都选
//有点类似于拯救大兵那题
#include
#include
using namespace std;
const int N = 1e3 + 10, M = N * N, K = 2 * N * N;//M:点数, K = 边数
struct Edge
{
int a, b, w;
}e[K];
int p[M];
int ids[N][N], cnt;//将二维坐标映射成1维
int n, m, k;
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
void get_edges()
{
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, -1, 0, 1}, dw[4] = {1, 2, 1, 2};//必须要按1212的顺序枚举,这样u%2的时候就可以先添加1的边再添加2的边,自己排序少一个快排logn的复杂度
for (int z = 0; z < 2; z ++ )//先枚举u%2余数为0的再枚举u%2余数为1的,余数为0说明是竖边权值为1,为1说明是横边权值为2
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
for (int u = 0; u < 4; u ++ )
{
if (u % 2 == z)
{
int x = i + dx[u], y = j + dy[u], w = dw[u];
int a = ids[i][j], b = ids[x][y];
if (a < b) e[k ++ ] = {a, b, w};//因为是无向边我们枚举一个就行了
}
}
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n * m; i ++ ) p[i] = i;
for (int i = 1;i <= n; i ++ )//将二维坐标映射成1维
for (int j = 1; j <= m; j ++ )
ids[i][j] = ++ cnt;
int x1, x2, y1, y2;
while(cin >> x1 >> y1 >> x2 >> y2)
{
int a = ids[x1][y1], b = ids[x2][y2];
p[find(a)] = find(b);
}
get_edges();//初始化e[]
int res = 0;
for (int i = 0; i < k; i ++ )
{
int a = find(e[i].a), b = find(e[i].b), w = e[i].w;
if (a != b)
{
p[a] = b;
res += w;
}
}
cout << res;
return 0;
}