一.题目链接:
POJ-1639
二.题目大意:
给定一张 N 个点 M 条边的无向图
求出无向图的一颗最小生成树
满足 1 号节点的度数不超过给定的整数 S.
三.分析:
模板题...
步骤:
① 去除 1 号节点后,对每个连通块求最小生成树.
② 在每个连通块中(共 m 个)选取与 1 号点最近的点连接,得到最小 m 度生成树.
③ 枚举要拆边连接到 1 号点的节点,选取最优解.
详见代码.
四.代码实现:
#include <bits/stdc++.h>
using namespace std;
const int M = (int)20;
const int inf = 0x3f3f3f3f;
int ans;
int n, m, k;
map <string, int> mp;
int dis[M + 5][M + 5];
struct enode
{
int u, v, w;
}Edge[(int)1e3 + 5], dp[M + 5];
int fa[M + 5];
int block_dis[M + 5];
int block_id[M + 5];
bool linked[M + 5][M + 5];
void init()
{
mp.clear();
mp["Park"] = 1;
memset(dis, inf, sizeof(dis));
}
void read()
{
scanf("%d", &m);
string stru, strv;
for(int i = 1, u, v, w; i <= m; ++i)
{
cin >> stru >> strv >> w;
if(!mp.count(stru)) mp[stru] = mp.size();
if(!mp.count(strv)) mp[strv] = mp.size();
u = mp[stru], v = mp[strv];
dis[u][v] = dis[v][u] = min(dis[u][v], w);
Edge[i * 2 - 1].u = u;
Edge[i * 2 - 1].v = v;
Edge[i * 2 - 1].w = w;
Edge[i * 2].u = v;
Edge[i * 2].v = u;
Edge[i * 2].w = w;
linked[u][v] = linked[v][u] = 1;
}
n = mp.size();
m *= 2;
for(int i = 1; i <= n; ++i)
{
fa[i] = i;
block_dis[i] = inf;
for(int j = 1; j <= n; ++j)
{
linked[i][j] = 0;
}
}
scanf("%d", &k);
}
bool cmp(enode a, enode b)
{
return a.w < b.w;
}
int tofind(int x)
{
if(x == fa[x]) return x;
return fa[x] = tofind(fa[x]);
}
void Kruskal()
{
sort(Edge + 1, Edge + m + 1, cmp);
for(int i = 1, fau, fav; i <= m; ++i)
{
fau = tofind(Edge[i].u);
fav = tofind(Edge[i].v);
if(fau == 1 || fav == 1) continue;
if(fau != fav)
{
ans += Edge[i].w;
fa[fau] = fav;
linked[Edge[i].u][Edge[i].v] = linked[Edge[i].v][Edge[i].u] = 1;
}
}
}
void work1()
{
for(int i = 2, fai; i <= n; ++i)
{
fai = tofind(i);
if(block_dis[fai] > dis[1][i])
{
block_dis[fai] = dis[1][i];
block_id[fai] = i;
}
}
for(int i = 2, fai; i <= n; ++i)
{
fai = tofind(i);
if(block_id[fai] == i)
{
--k;
ans += block_dis[fai];
linked[1][i] = linked[i][1] = 1;
}
}
}
void dfs(int u, int fa)
{
for(int i = 2; i <= n; ++i)
{
if(fa != i && linked[u][i])
{
if(dp[u].w >= dis[u][i])
dp[i] = dp[u];
else
{
dp[i].u = u;
dp[i].v = i;
dp[i].w = dis[u][i];
}
dfs(i, u);
}
}
}
void work2()
{
int id;
enode tar;
while((k--) > 0)
{
tar.w = inf;
for(int i = 2; i <= n; ++i)
dp[i].w = -inf;
dfs(1, 0);
for(int i = 2; i <= n; ++i)
{
if(tar.w > dis[1][i] - dp[i].w)
{
id = i;
tar = dp[i];
tar.w = dis[1][i] - dp[i].w;
}
}
if(tar.w >= 0) break;
ans += tar.w;
linked[1][id] = linked[id][1] = 1;
linked[tar.u][tar.v] = linked[tar.v][tar.u] = 0;
}
}
int main()
{
init();
read();
Kruskal();
work1();
work2();
printf("Total miles driven: %d\n", ans);
return 0;
}