CCF201812-4题-数据中心(100分)

 这道题我最开始用了Prim算法求解,后来发现不能满足时间要求,只得了70分,换成kruskal算法实现以后就满分了,kruskal算法适用于稀疏的图,其复杂度主要在于对边的排序,复杂度为O(nlogn),而prim算法思路和dijkstra算法很像,适用于稠密图,复杂度为O(n2)下面贴了两种算法的代码。

试题编号: 201812-4
试题名称: 数据中心
时间限制: 1.0s
内存限制: 512.0MB
问题描述:


样例输入

4
5
1
1 2 3
1 3 4
1 4 5
2 3 8
3 4 2

样例输出

4

样例说明

  下图是样例说明。

1.prim算法(70)分

#include 
#include 
using namespace std;
struct adj {
    long long to;
    long long value;
}Adj;
const long long MAXV = 500001;
const long long INF = 1 << 30;
long d[MAXV];//离S集合最近的地方
bool vis[MAXV] = { false };	//是否已经拜访
vector adjs[MAXV];		//用来存放边
int n, m;//顶点数和边数
int Prim(long long v0) {
    long long maxadj = 0;
    fill(d, d + MAXV, INF);
    d[v0] = 0;
    for (long long i = 1; i <= n; i++) {
	long long MIN = INF, u = -1;
	for (long long j = 1; j <= n; j++) {
	    if (vis[j] == false && MIN > d[j]) {
		MIN = d[j];
		u = j;
	    }
	}
	if (u == -1)
	    return -1;
	//找最小生成树中的最大边
	if (maxadj < d[u]) {
	    maxadj = d[u];
	}
	vis[u] = true;//已经访问过
	for (vector::iterator it = adjs[u].begin(); it != adjs[u].end(); it++) {
	    if (d[it->to] > it->value && vis[it->to] == false) {
		d[it->to] = it->value;
	    }
	}
    }
    return maxadj;
}
int main()
{
    long long v0;
    cin >> n >> m >> v0;
    for (long long i = 1; i < m; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        Adj.to = b;
        Adj.value = c;
        adjs[a].push_back(Adj);
        Adj.to = a;
        adjs[b].push_back(Adj);
    }
    cout << Prim(v0);
}

2.kruskal算法(100分)

#include 
#include 
#include 
using namespace std;
const long long MAXV = 500001;
int n, m;//顶点数和边数
int father[MAXV];
struct adj {
    long long u,v;
    long long value;
}Adj;
//算法排序比较函数
bool cmp(adj x,adj y){
    return x.value < y.value;
}
vector adjs;//边集
//并查集搜索函数
int fatherfind(int x) {
    int a = x;
    while (x != father[x]) {
	x = father[x];
    }
    //路径压缩
    while (a != father[a]) {
	int z = a;
	a = father[a];
	father[z] = x;
    }
    return x;
}
int kruskal() {
    int maxadj = 0;//需要找到的最大边,即为Tmax
    //初始化并查集
    for (int i = 1; i <= n; i++) {
	father[i] = i;
    }
    //排序
    sort(adjs.begin(), adjs.end(), cmp);
    for (vector::iterator it = adjs.begin(); it != adjs.end(); it++) {
	int faU = fatherfind(it->u);
	int faV = fatherfind(it->v);
	if (faU != faV) {		//如果边的两点不是在同一个集合
	    father[faU] = faV;	//合并两个子集合
	    if (maxadj < it->value) {//找到最小生成树中的最大边
		maxadj = it->value;
	    }
	}
    }
    return maxadj;
}
int main() {
    int v0;
    cin >> n >> m;
    cin >> v0;
    for (int i = 1; i <=m; i++) {
	cin >> Adj.u >> Adj.v >> Adj.value;
	adjs.push_back(Adj);
    }
    cout << kruskal();
}

 

 

你可能感兴趣的:(ccf)