http://poj.org/problem?id=1639
题意:
见黑书。
思路:
最小限制树模板题:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>
#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x) ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)
#define ll long long
#define inf 0x7f7f7f7f
#define MOD 1073741824
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 150
#define N 35
using namespace std;
//freopen("din.txt","r",stdin);
struct node
{
int u,w;
node(int _u,int _w)
{
u = _u;
w = _w;
}
friend bool operator < (node a,node b)
{
return a.w > b.w;
}
};
int dis[N],pre[N];
int col[N],near[N];
int Msd[N];
int mat[N][N];
priority_queue<node>q;
map<string,int>mp;
int res,n;
int prim(int s,int id)
{
int res = 0,i;
while (!q.empty()) q.pop();
q.push(node(s,0));
dis[s] = 0;
while (!q.empty())
{
node cur = q.top(); q.pop();
int u = cur.u;
int w = cur.w;
if (!col[u])
{
col[u] = id;
res += w;
for (i = 1; i <= n; ++i)
{
if (!col[i] && mat[u][i] && dis[i] > mat[u][i])
{
dis[i] = mat[u][i];
pre[i] = u;
q.push(node(i,dis[i]));
}
}
}
}
return res;
}
void dfs(int u,int fa,int maxside)
{
Msd[u] = maxside > mat[fa][u] ? maxside : mat[fa][u];
for (int i = 1; i <= n; ++i)
{
if (mat[u][i] && i != fa && (pre[u] == i || pre[i] == u))
dfs(i,u,Msd[u]);
}
}
void solve(int k)
{
int i;
for (i = 0; i <= n; ++i)
{
dis[i] = inf;
col[i] = 0;
pre[i] = 0;
near[i] = 0;
}
col[0] = 1;//标记每一个最小生成树,先将根节点计入1
res = 0;
int num = 0;
for (i = 1; i <= n; ++i)
{
if (!col[i]) res += prim(i,++num);//分别计算最小生成树
}
//计算每个最小生成树里距离s的最短距离
for (i = 1; i <= n; ++i)
{
int mk = col[i];
if (mat[0][i] && (near[mk] == 0 || mat[0][i] < mat[0][near[mk]]))
near[mk] = i;
}
//连接每个最小生成树到根节点s的最短距离同时更新每个节点可能连接的最大边权值
CL(Msd,0);
for (i = 1; i <= num; ++i)
{
res += mat[0][near[i]];
mat[0][near[i]] = mat[near[i]][0] = 0;//将该点消除
dfs(near[i],0,0);//求出改最小生成树以0为根节点的树根到每个节点之间的最大边权值
}
k = k - num;//此时形成num度最小生成树
while (k--)
{
int tmp = 0;//找出Msd[tmp] - mat[0][tmp]的最大值
for (i = 1; i <= n; ++i)
{
if (mat[0][i] && (tmp == 0 || Msd[tmp] - mat[0][tmp] < Msd[i] - mat[0][i]))
tmp = i;
}
if (Msd[tmp] <= mat[0][tmp]) break;//如果不能使度限制生成树继续减小跳出
res -= (Msd[tmp] - mat[0][tmp]);
mat[0][tmp] = mat[tmp][0] = 0;//将改变置为0,表示不能再枚举了,已经加入最小限度生成树
//
int p = 0;
for (i = tmp; pre[i] != 0; i = pre[i])
{
if (p == 0 || mat[p][pre[p]] < mat[i][pre[i]]) p = i;
}
pre[p] = 0;
dfs(tmp,0,0);
}
printf("Total miles driven: %d\n",res);
}
int main()
{
int i,m;
string s1,s2;
int w;
while (~scanf("%d",&m))
{
mp.clear();
CL(mat,0);
mp["Park"] = 0; n = 0;
//printf("%d\n",mp.count("Park"));
for (i = 0; i < m; ++i)
{
cin>>s1>>s2>>w;
if (!mp.count(s1)) mp[s1] = ++n;
if (!mp.count(s2)) mp[s2] = ++n;
int tx = mp[s1];
int ty = mp[s2];
//建图
if (!mat[tx][ty] || mat[tx][ty] > w)
mat[tx][ty] = mat[ty][tx] = w;
}
int k;
cin>>k;
solve(k);
}
return 0;
}