题解
使用kruskal求解,创建一个虚拟点0方便处理。
将每个点本身的权值作为和虚拟点连接的边权,k个已习得的点和虚拟点建立0权边。普通关系就把两个点建立对应代价的边。
由于数据输入量较大使用fread快读,并查集使用路径压缩+启发式合并优化。
AC代码
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
int n, m, k;
ll t;
int fz[N], sz[N];
inline void find(int &x)
{
while (x != fz[x]) //非递归
x = fz[x] = fz[fz[x]];
}
inline void merge(int x, int y)
{
find(x), find(y);
if (sz[x] > sz[y]) //启发式合并
swap(x, y);
fz[x] = y;
sz[y] += sz[x];
}
struct node
{
int u, v, w;
bool operator < (const node &o) const
{
return w < o.w;
}
}e[N * 7];
int idx;
//fread高速读入 如果用则全部都要用read不能再scanf或cin 测试需要重定向从文件输入数据
namespace fastIO {
#define BUF_SIZE 100000
//fread -> read
bool IOerror = 0;
inline char nc() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if (p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if (pend == p1) {
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
inline void read(int &x) {
char ch;
while (blank(ch = nc()));
if (IOerror) return;
for (x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
}
inline void read(ll &x) {
char ch;
while (blank(ch = nc()));
if (IOerror) return;
for (x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
}
#undef BUF_SIZE
};
using namespace fastIO;
ll kruskal()
{
sort(e, e + idx);
ll res = 0;
for (int i = 0; i < idx; ++i)
{
int u = e[i].u, v = e[i].v, w = e[i].w;
//u = find(u), v = find(v);
find(u), find(v);
if (u != v)
{
merge(u, v);
res += w;
}
}
return res;
}
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
read(n), read(m), read(k), read(t);
int x;
sz[0] = 1;
for (int i = 1; i <= n; ++i)
{
fz[i] = i; //初始化并查集
sz[i] = 1;
read(x);
e[idx++] = { 0, i, x }; //每个节点和虚拟节点0创建边 边权为点代价
}
for (int i = 0; i < k; ++i)
{
read(x);
e[idx++] = { 0, x, 0 }; //已有节点和虚拟节点0创建0代价边
}
int u, v, w;
for (int i = 0; i < m; ++i)
{
read(u), read(v), read(w);
e[idx++] = { u, v, w };
}
ll res = kruskal();
printf("%s\n", res <= t ? "Yes" : "No");
return 0;
}

本文介绍了一种利用Kruskal算法解决特定图论问题的方法。通过引入虚拟节点简化问题处理,采用快速读取和并查集优化技术提高效率。适用于大数据量的最小生成树问题。
1376

被折叠的 条评论
为什么被折叠?



