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;
}
题意及思路:求最小生成树及次小生成树 (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;
}
相关文章推荐
- (beginer) 最小生成树 UVA 10600 ACM Contest and Blackout
- UVA 10600 ACM Contest and Blackout(最小生成树and次小生成树)
- UVA 10600 - ACM Contest and Blackout(最小生成树&次小生成树)
- UVa 10600 - ACM Contest and Blackout(最小生成树)
- 【UVa】10600 ACM Contest and Blackout 次小生成树
- uva10600 - ACM Contest and Blackout 次小生成树
- ACM Contest and Blackout - UVA 10600 - 次小生成树
- 【UVA 10600】 ACM Contest and Blackout(最小生成树和次小生成树)
- UVA 10600 - ACM Contest and Blackout 次小生成树
- UVA 10600 - ACM Contest and Blackout 次小生成树
- UVA - 10600 ACM Contest and Blackout(次小生成树)
- UVA 10600 ACM Contest and Blackout 次小生成树/裸
- UVa 10600 ACM contest and Blackout( 次小生成树)
- UVa10600 ACM Contest and Blackout
- uva 10600 ACM Contest and Blackout(次小生成树)
- UVA 10600 ACM Contest and Blackout (次小生成树)
- UVA-10600 ACM Contest and Blackout (次小生成树)
- uva 10600 - ACM Contest and Blackout(次小生成树)
- UVA 10600 ACM Contest and Blackout(次小生成树)
- UVa 10600__ACM Contest and Blackout(次小生成树)