# [poj1639]度限制生成树

## Problem Description

The Contortion Brothers are a famous set of circus clowns, known worldwide for their incredible ability to cram an unlimited number of themselves into even the smallest vehicle. During the off-season, the brothers like to get together for an Annual Contortionists Meeting at a local park. However, the brothers are not only tight with regard to cramped quarters, but with money as well, so they try to find the way to get everyone to the party which minimizes the number of miles put on everyone’s cars (thus saving gas, wear and tear, etc.). To this end they are willing to cram themselves into as few cars as necessary to minimize the total number of miles put on all their cars together. This often results in many brothers driving to one brother’s house, leaving all but one car there and piling into the remaining one. There is a constraint at the park, however: the parking lot at the picnic site can only hold a limited number of cars, so that must be factored into the overall miserly calculation. Also, due to an entrance fee to the park, once any brother’s car arrives at the park it is there to stay; he will not drop off his passengers and then leave to pick up other brothers. Now for your average circus clan, solving this problem is a challenge, so it is left to you to write a program to solve their milage minimization problem.

## 算法思路

1. 这个算法在某个大牛的博客里被反复的提及。
2. 首先，我们将V0排除，建立若干个连通分支树。即使用Prim算法构造最小生成树。
3. 然后，选择最短的边将这个图变成连通图。此时计算从V0出发到达每个点当中最长的边。
4. 然后，在允许的度限制的范围内，反复加入与V0相关的边，每次加入一条边的时候，都会形成一个环，此时就删去这个环上最长的边。可以保证得到的生成树的权值最短。
5. 说的这么轻松，但是实现起来还是十分麻烦的，下面附代码。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;

#define MAXN 25
#define INF 0x3f3f3f3f

struct Edge{
int u,v,len,next;
}EdgeTable[MAXN*MAXN*4];

struct Node{
int id,dis;
Node(){}
Node(int a,int b){
id=a;
dis=b;
}
friend bool operator<(Node a,Node b){
return a.dis>b.dis;
}
};

char nameList[MAXN][15];
int n,m,k,cnt,e;
int maxside[MAXN],fst[MAXN];
int pre[MAXN];
int clo[MAXN];
int dist[MAXN];

void Init()
{
strcpy(nameList[0],"Park");
memset(pre,0,sizeof(pre));
memset(clo,-1,sizeof(clo));
memset(dist,INF,sizeof(dist));
memset(maxside,0,sizeof(maxside));
memset(fst,-1,sizeof(fst));
n=1;
cnt=0;
e=0;
}

int LocQuery(char* name)
{
int i;
for(i=0;i<n;i++){
if(strcmp(name,nameList[i])==0)
return i;
}
strcpy(nameList[n],name);
return n++;
}

{
EdgeTable[e].u=from;
EdgeTable[e].v=to;
EdgeTable[e].len=len;
}

int Prim(int s)
{
int i;
int res=0;
priority_queue<Node>Q;
Q.push(Node(s,0));
dist[s]=0;

while(!Q.empty()){
Node cur = Q.top();
Q.pop();

if(clo[cur.id]<0){
clo[cur.id]=cnt;
res += dist[cur.id];

int dest = EdgeTable[i].v;
if(dest!=0&&dist[dest]>EdgeTable[i].len&&clo[dest]<0){
pre[dest]=cur.id;
dist[dest] = EdgeTable[i].len;
Q.push(Node(dest,dist[dest]));
}
}
}
}
return res;
}

void Dfs(int cur,int fa,int lastEdge,int maxEdge)
{
if(EdgeTable[lastEdge].len>EdgeTable[maxEdge].len)
maxside[cur]=lastEdge;
else
maxside[cur]=maxEdge;
int i;

if(EdgeTable[i].len!=0&&EdgeTable[i].v!=fa&&(pre[EdgeTable[i].v]==cur||pre[cur]==EdgeTable[i].v))
Dfs(EdgeTable[i].v,cur,i,maxside[cur]);
}

return;
}

void Solve()
{
int i;
int ans=0;

for(i=1;i<n;i++){
if(clo[i]<0){
ans += Prim(i);
cnt++;
}
}

//Compute the min length edge from V0 to every
//subtrees
int id = clo[EdgeTable[i].v];
if(fst[id]<0||EdgeTable[fst[id]].len>EdgeTable[i].len){
fst[id] = i;
}
}

for(i=0;i<cnt;i++){
//Compute the max length edge in the route from V0
//to every point Vn
ans += EdgeTable[fst[i]].len;
EdgeTable[fst[i]].len = EdgeTable[fst[i]^1].len = 0;
Dfs(EdgeTable[fst[i]].v,0,fst[i],fst[i]);
}
k=k-cnt;

while(k--){
int tmp=-1;
int tmp2=-1;
int tmp3=-1;
int dest = EdgeTable[i].v;
if(EdgeTable[i].len>0){
if(EdgeTable[maxside[dest]].len-EdgeTable[i].len>tmp2){
tmp=dest;
tmp2=EdgeTable[maxside[dest]].len-EdgeTable[i].len;
tmp3=i;
}
}
}

if(tmp<0||tmp2<0)break;
ans -= tmp2;
//Delete the edge
EdgeTable[maxside[tmp]].len = EdgeTable[maxside[tmp]^1].len=0;
EdgeTable[tmp3].len = EdgeTable[tmp3^1].len = 0;
int u = EdgeTable[maxside[tmp]].u;
int v = EdgeTable[maxside[tmp]].v;

Dfs(tmp,0,tmp3,tmp3);
}
printf("Total miles driven: %d\n",ans);
return;
}

int main()
{
freopen("input","r",stdin);
int i,tmp;
char str1[15],str2[15];
while(scanf("%d",&m)!=EOF){
Init();

for(i=0;i<m;i++){
scanf("%s %s %d",str1,str2,&tmp);
int index1 = LocQuery(str1);
int index2 = LocQuery(str2);
}

scanf("%d",&k);

Solve();
}
return 0;
}

#### POJ 1639度限制生成树

2016-10-15 20:20:54

#### 【hdu3710】Battle over Cities【树链剖分+最小生成树】

2017-12-04 22:16:19

#### PAT 1030. Travel Plan Dijkstra多边权

2018-02-12 21:15:35

#### 最小度限制生成树 POJ1639

2017-07-10 19:18:27

#### [BZOJ1073][SCOI2007]kshort

2016-02-20 21:19:11

#### poj1639 Picnic Planning 限制顶点度数的MST

2015-01-20 16:43:49

#### poj1639:最小度限制生成树

2016-08-22 20:51:01

#### 最小k度限制生成树

2013-04-09 20:48:29

#### 度限制最小生成树源码

2009年10月08日 4KB 下载

#### 最小K度限制生成树

2017-01-16 16:55:29