您的位置:首页 > 其它

51Nod-1640-天气晴朗的魔法

2016-08-16 23:15 316 查看
ACM模版

描述



题解

这道题如果看清楚题意,那其实思路很容易想起来。分析题意可以得知,答案要求满足两个条件:

第一优先条件是,生成的树的最大边权必须最小;

第二优先条件是,生成树的总权值和要求最大。

分析第一个条件,我们需要使用
Kruskal_0
来求最小生成树,并且记录下来该种情况下,最大的边权
MAXW


接着分析第二个条件,我们顺理成章的可以想到最大生成树,但是这个最大生成树的边不能大于
MAXW
,所以我们需要用到
Kruskal_1
函数,这是一个求有最大边权限制的最大生成树代码段,返回生成树的权值和。

这里说明一下,之所以都使用
Kruskal
算法是因为该算法求最小和最大生成树的差异就在于排序部分,当然,我们也可以将排序部分抽离出来,统一排序方案,不过内部遍历方向要适当改变。要注意返回值返回的是什么。

代码

#include <iostream>
#include <algorithm>
#include <cstring>

typedef long long ll;

using namespace std;

const int MAXN = 1e5 + 10;
const int MAXM = 2 * MAXN;

int F[MAXN];    //  并查集
int MAXW = 0;

struct edge
{
int u;      //  起点
int v;      //  终点
int w;      //  权值
} Edge[MAXM];   //  存储边信息

int tol = 0;    //  边数

void addEdge(int u, int v, int w)
{
Edge[tol].u = u;
Edge[tol].v = v;
Edge[tol++].w = w;
return ;
}

//  从小到大排
bool cmp_0(edge a, edge b)
{
return a.w < b.w;
}

//  从大到小排
bool cmp_1(edge a, edge b)
{
return a.w > b.w;
}

int find(int x)
{
if (F[x] == -1)
{
return x;
}
else
{
return F[x] = find(F[x]);
}
}

//  最小生成树
int Kruskal_0(int n)  //  传入点数,返回最小生成树的最大边权值,如果不连通返回-1
{
memset(F, -1, sizeof(F));
sort(Edge, Edge + tol, cmp_0);
int cnt = 0;    //  计算加入边数
int ans = 0;
for (int i = 0; i < tol; i++)
{
int u = Edge[i].u;
int v = Edge[i].v;
int w = Edge[i].w;
int tOne = find(u);
int tTwo = find(v);
if (tOne != tTwo)
{
if (ans < w)
{
ans = w;
}
F[tOne] = tTwo;
cnt++;
}
if (cnt == n - 1)
{
break;
}
}
if (cnt < n - 1)
{
return -1;
}
else
{
return ans;
}
}

//  最大生成树(有最大边权限制)
ll Kruskal_1(int n)  //  传入点数,返回最大生成树的权值,如果不连通返回-1
{
memset(F, -1, sizeof(F));
sort(Edge, Edge + tol, cmp_1);
int cnt = 0;    //  计算加入边数
ll ans = 0;
for (int i = 0; i < tol; i++)
{
if (Edge[i].w > MAXW)
{
continue;
}
int u = Edge[i].u;
int v = Edge[i].v;
int w = Edge[i].w;
int tOne = find(u);
int tTwo = find(v);
if (tOne != tTwo)
{
ans += w;
F[tOne] = tTwo;
cnt++;
}
if (cnt == n - 1)
{
break;
}
}
if (cnt < n - 1)
{
return -1;
}
else
{
return ans;
}
}

int main(int argc, const char * argv[])
{
//    freopen("/Users/zyj/Desktop/input.txt", "r", stdin);

int N, M;
cin >> N >> M;

int A, B, V;
for (int i = 0; i < M; i++)
{
cin >> A >> B >> V;
addEdge(A, B, V);
}

MAXW = Kruskal_0(N);

ll ans = Kruskal_1(N);

cout << ans << '\n';

return 0;
}


参考

《最小生成树》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  图论 最小生成树