您的位置:首页 > 其它

UVA 10600 ACM Contest and Blackout (次小生成树 Kruskal 封装)

2014-11-05 19:40 337 查看
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=54643#problem/R

题意及思路:求最小生成树及次小生成树 (Kruskal 模板,找到两点间权值最大的那条边)

#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

const int maxn = 100 + 10;
const int INF = 1000000000;

struct edge
{
int u, v, w;
edge(){}
edge(int u, int v, int w) : u(u), v(v), w(w) {}
bool operator < (const edge &rhs) const
{
return w < rhs.w;
}
};

struct MST
{
int n, m;
edge e[maxn * maxn];//储存所有的边
int fa[maxn];
vector <int> G[maxn];//储存生成树中每个点相邻的点
vector <int> ed[maxn];//储存相应的边的权
vector <int> nodes;//储存已经遍历过的节点
int Max[maxn][maxn];//储存最小生成树中,u、v唯一路径上的最大权值
int vis[maxn*maxn];

//这里是把无根树,转为了有根树,具体做法:
//在初始调用时Dfs(0,-1,0),然后后面节点拓展儿子时,不允许向回走
void dfs(int u, int fa, int facost)
{
//先对当前点同所有已访问过的节点,进行更新
for(int i = 0; i < nodes.size(); i++)
{
int x = nodes[i];
Max[u][x] = Max[x][u] = max(Max[x][fa], facost);
}
nodes.push_back(u);
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if(v != fa)
dfs(v, u, ed[u][i]);
}
}

void init(int n)
{
this -> n = n;
m = 0;
memset(Max, 0, sizeof(Max));
memset(vis, 0, sizeof(vis));
nodes.clear();
for(int i = 0; i < n; i++)
{
fa[i] = i;
G[i].clear();
ed[i].clear();
}
}

void add(int u, int v, int w)
{
e[m++] = edge(u, v, w);
}

int Find(int x)
{
return fa[x] != x ? fa[x] = Find(fa[x]) : x;
}

int solve()
{
sort(e, e + m);
int cnt = 0;
int ans = 0;
for(int i = 0; i < m; i++)
{
int x = e[i].u, y = e[i].v, fx = Find(x), fy = Find(y);
int d = e[i].w;
if(fx != fy)
{
vis[i] = 1;
fa[fx] = fy;
G[x].push_back(y);
ed[x].push_back(d);
G[y].push_back(x);
ed[y].push_back(d);
ans += d;
if(++cnt == n - 1)
break;
}
}
return ans;
}
};

MST tr;

int main()
{
int t, n, m;
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &n, &m);
tr.init(n);
for(int i = 0; i < m; i++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
tr.add(a - 1, b - 1, c);
}
int ans1 = tr.solve();
int ans2 = INF;
tr.dfs(0, -1, 0);
for(int i = 0; i < m; i++)
{
if(!tr.vis[i])
{
int x = tr.e[i].u;
int y = tr.e[i].v;
int d = tr.e[i].w;
ans2 = min(ans2, ans1 + d - tr.Max[x][y]);
}
}
printf("%d %d\n", ans1, ans2);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: