[poj1639]度限制生成树

原创 2016年08月28日 23:14:51

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 head[MAXN];
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(head,-1,sizeof(head));
    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;
}

//Add new location
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++;
}

void addEdge(int from,int to,int len)
{
    EdgeTable[e].u=from;
    EdgeTable[e].v=to;
    EdgeTable[e].len=len;
    EdgeTable[e].next=head[from];
    head[from]=e++;
}

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];

            for(i=head[cur.id];i!=-1;i=EdgeTable[i].next){
                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;

    for(i=head[cur];i!=-1;i=EdgeTable[i].next){
        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++;
        }
    }

    for(i=head[0];i!=-1;i=EdgeTable[i].next){
        //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;
        for(i=head[0];i!=-1;i=EdgeTable[i].next){
            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);
        addEdge(index1,index2,tmp);
        addEdge(index2,index1,tmp);
    }

    scanf("%d",&k);

    Solve();
    }
    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

A Simple Problem with Integers POJ - 3468 (线段树区间增减,区间查询模板)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Subm...

POJ1985+POJ2631 求一棵树的直径

这两个题目都是求解一棵树的直径,也就是书里面的最长的一段距离。 树的直径是指树的最长简单路。求法: 两遍BFS(dfs) :先任选一个起点BFS(dfs)找到最长路的终点,再从终点进行BFS...

P300-野餐计划(POJ-1639最小度限制生成树)

黑书上的例题,具体模型是求一个无向图的最小生成树,其中有一个点的度有限制(假设为 k)。   要求最小 k 度生成树,我们可以按照下面的步骤来做: 设有度限制的点为 V0 ,V0称为根节点 1...

poj_1639 Picnic Planning(度限制最小生成树)

Picnic Planning Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 10431   Accepted:...

POJ 1639:Picnic Planning(最小度限制生成树)

Picnic Planning Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 7356  ...
  • wugj03
  • wugj03
  • 2012年04月18日 12:34
  • 817

poj1639最小度限制生成树(kruscal+邻接表)

一、.思路 设限制结点为des.  1. 求去掉des的最小生成树,此时求出来的是最小生成森林  2.添加des到各连通分量的边,当然取最小的边。  3.此时得到m度的生成树,我们要求的是小于...
  • ysjjovo
  • ysjjovo
  • 2011年08月13日 11:51
  • 469

[POJ 1639] 单度限制最小生成树

POJ 1639 Picnic Planning 单度限制最小生成树
  • SIOFive
  • SIOFive
  • 2014年04月10日 01:05
  • 916

POJ 1639 度限制最小生成树Prim

题意:给出n条无向带权边,求所有点的最小生成树,其中“Park”的度数不超过最后输入的k,输入保证有解。 思路:思路其实很好理解,分为几个步骤: 1.当然将“Park”作为根节点,一开始先删掉它,则原...
  • dy0607
  • dy0607
  • 2016年10月12日 00:17
  • 220

最小度限制生成树 POJ1639

今天了解了一下最小度限制生成树。这个问题的本质依旧是生成树,但是对于某个点的度给定限制。也就是连到该点上的边不能超过限制的数量limit。 具体的解决过程和相关的证明可以看一下《最小生成树问题的扩展...

POJ 1639 Picnic Planning(初遇最小度限制生成树)

这是最小度限制生成树的经典问题,题意就不说了 题目链接:http://poj.org/problem?id=1639 一般都是1个顶点的度有限制k,如果每个顶点的度都有限制,那么当前是NP难的。 为了...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[poj1639]度限制生成树
举报原因:
原因补充:

(最多只允许输入30个字)