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

来源:互联网 发布:血与酒 石之心 知乎 编辑:程序博客网 时间:2024/05/16 12:54
Picnic Planning
Time Limit: 5000MS Memory Limit: 10000KTotal Submissions: 10828 Accepted: 3915

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.

Input

Input will consist of one problem instance. The first line will contain a single integer n indicating the number of highway connections between brothers or between brothers and the park. The next n lines will contain one connection per line, of the form name1 name2 dist, where name1 and name2 are either the names of two brothers or the word Park and a brother's name (in either order), and dist is the integer distance between them. These roads will all be 2-way roads, and dist will always be positive.The maximum number of brothers will be 20 and the maximumlength of any name will be 10 characters.Following these n lines will be one final line containing an integer s which specifies the number of cars which can fit in the parking lot of the picnic site. You may assume that there is a path from every brother's house to the park and that a solution exists for each problem instance.

Output

Output should consist of one line of the form 
Total miles driven: xxx 
where xxx is the total number of miles driven by all the brothers' cars.

Sample Input

10Alphonzo Bernardo 32Alphonzo Park 57Alphonzo Eduardo 43Bernardo Park 19Bernardo Clemenzi 82Clemenzi Park 65Clemenzi Herb 90Clemenzi Eduardo 109Park Herb 24Herb Eduardo 793

Sample Output

Total miles driven: 183

Source

East Central North America 2000

题意:以Park为根,然后给出n条边,求Park度数小于等于k的最小生成树权值。

分析:除开这里的输入需要一点处理之外,这道题就是一道度限制最小生成树的模板题了吧。所谓的度限制最小生成树就是对于某个点,求该点的度数小于等于k时最小生成树。在这道题中,就是求1点的度数小于等于k时的最小生成树。由于不知道1点最后的度数是多少,那么我们先处理1以外的点。对除1之外的点做最小生成树,当处理完这n-1个点之后,会出现某些联通块,令联通块的个数为m的话,然后再求1点到每个联通块的最小权值,这一步之后,会构成包含1点的生成树,此时1点的度数是m,那么接下来我们可以求出1点的度数为m+1,m+2等等情况。下面的步骤跟求次小生成树的步骤差不多,我们首先从1点对整棵树进行遍历,用dp[v]表示1到达v的路径中的最大权值,然后枚举去掉生成树中某些边v``同时加入edge[1][v``],取其中的最小值。由于我们求的只是最小生成树,如果其中的最小增值=插入的边-删除的边>=0的话,说明当前的权值就是我们要求的k度最小生成树权值,那就可以直接输出答案了。由于我们在m度之后再往生成树中加边会形成环,那么此时要去掉某条边,枚举可以去掉的并且没有跟1相连的边,再加入与1相连的边,求最小,就是最后答案。

代码:
#include<cstring>#include<cstdio>#include<algorithm>#include<string>#include<map>using namespace std;struct Edge{    int u,v,w,next,id;};int cnt;int head[1005];int n;int p[1005];int num;int vis[1005];int Max[1005];int to[1005];Edge edge[10005],edge_temp[10005],dp[10005];void add(int u,int v,int w){    edge[cnt].u=u;    edge[cnt].v=v;    edge[cnt].w=w;    edge[cnt].next=head[u];    head[u]=cnt++;}bool cmp(Edge t1,Edge t2){    return t1.w<t2.w;}int find1(int x){    if(p[x]==x){        return x;    }    return p[x]=find1(p[x]);}int kruscal(){    int ans=0;    sort(edge_temp+1,edge_temp+1+n,cmp);    for(int i=1;i<=n;i++){        int u=edge_temp[i].u;        int v=edge_temp[i].v;        int w=edge_temp[i].w;        if(u!=1){            int t1=find1(u);            int t2=find1(v);            if(t1!=t2){                to[v]=w;                ans+=w;                p[t1]=t2;                swap(u,v);                add(u,v,w);                add(v,u,w);            }        }    }    return ans;}void dfs(int cur,int pre){    for(int i=head[cur];i!=-1;i=edge[i].next){        int v=edge[i].v;        int w=edge[i].w;        if(v!=pre){            if(dp[v].w!=-1){                if(w>dp[cur].w){                    dp[v].w=w;                    dp[v].u=cur;                    dp[v].v=v;                }                else{                    dp[v]=dp[cur];                }            }            dfs(v,cur);        }    }}int main(){    while(~scanf("%d",&n)){        map<string,int> name;        num=0;        cnt=0;        name["Park"]=++num;        for(int i=1;i<=n;i++){            head[i]=-1;            p[i]=i;            vis[i]=0;            Max[i]=0x3f3f3f3f;            to[i]=0;        }        for(int i=1;i<=n;i++){            char str1[20],str2[20];            int w;            scanf("%s%s%d",str1,str2,&w);            if(!name[str1]){                name[str1]=++num;            }            if(!name[str2]){                name[str2]=++num;            }            int u=name[str1];            int v=name[str2];            if(u>v){                swap(u,v);            }            edge_temp[i].u=u;            edge_temp[i].v=v;            edge_temp[i].w=w;            edge_temp[i].id=i;        }        int ans=kruscal();        int k,k_temp=0;        scanf("%d",&k);        for(int i=1;i<=n;i++){            int u=edge_temp[i].u;            int v=edge_temp[i].v;            int w=edge_temp[i].w;        }        for(int i=1;i<=n;i++){            int u=edge_temp[i].u;            int v=edge_temp[i].v;            int w=edge_temp[i].w;            int t1=find1(v);            if(u==1&&vis[t1]==0){                add(u,v,w);                dp[v].w=-1;                Max[v]=-1;                k_temp++;                ans+=w;                vis[t1]=1;            }        }        for(int i=k_temp+1;i<=k;i++){            for(int j=2;j<=num;j++){                if(Max[j]==-1){                    dp[j].w=-1;                }                else{                    dp[j].w=0;                }            }            dfs(1,-1);            int Min=0x3f3f3f3f;            int pos;            for(int j=1;j<=n;j++){                int u=edge_temp[j].u;                int v=edge_temp[j].v;                int w=edge_temp[j].w;                if(u==1&&dp[v].w!=-1){                    if(Min>w-dp[v].w){                        Min=w-dp[v].w;                        pos=v;                    }                }            }            if(Min>=0){                break;            }            else{                Max[pos]=-1;                ans+=Min;            }        }        printf("Total miles driven: %d\n",ans);    }    return 0;}


原创粉丝点击