K度限制MST poj 1639

/*
k度限制MST:有一个点的度<=k的MST
poj 1639
要求1号点的度不超过k 求MST
我们先把1号点扔掉 跑MST
假设有sum个连通分支 然后把这sum个分支连到1上
就得到了一个sum度的MST
这里往上连的时候 我们连这个分支里 距离1最近的
然后我们在1上加一条边 (即加一个度)得到sum+1度的MST
这里加边的时候 1连出去的每一条边都试一遍 取最小
假设当前1连到了 i 因为原来是个树 这样一搞就形成一个环
我们现在要删去环里面最长边 来得到更小的ans
我么维护dp[x]代表x到1的路径上权值最大的边的信息
(不包含与1直接相连的边否则删去1的度减1 并不能得到sum+1度的MST)
关键就是维护这个dp[x]
每次找sum+i度的MST之前我们从1dp一遍维护到每个点的max(沿着sum+i-1度的MST)
在树上跑 复杂度就降下来了On可以搞完
方程是 dp[x]=max(dp[from],G[from][x])
当新填的边不比找到的max边大的时候停下
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
#define maxn 110
using namespace std;
int n,m,k,num,G[maxn][maxn],vis[maxn][maxn],ans,mt[maxn],wh[maxn],sum,fa[maxn];
map<string,int>f;
struct node{
    int u,v,t;
}e[maxn*maxn],dp[maxn*maxn];
int cmp(const node &A,const node &B){
    return A.t<B.t;
}
void Add(int from,int to,int dis){
    num++;e[num].v=to;
    e[num].u=from;
    e[num].t=dis;
}
int find(int x){
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
void Dfs(int now,int from){
    for(int i=2;i<=n;i++){
        if(i==from)continue;
        if(vis[now][i]){
            if(dp[i].t!=-1){
                if(dp[now].t<G[now][i]){
                    dp[i].t=G[now][i];
                    dp[i].u=now;dp[i].v=i;
                }
                else dp[i]=dp[now];
            }
            Dfs(i,now);
        }
    }
}
void Kur(){
    sort(e+1,e+1+num,cmp);
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++){
        if(e[i].u==1||e[i].v==1)continue;
        if(find(e[i].u)==find(e[i].v))continue;
        ans+=e[i].t;fa[find(e[i].u)]=find(e[i].v);
        vis[e[i].u][e[i].v]=vis[e[i].v][e[i].u]=1;
    }
}
int main(){
    scanf("%d",&m);f["Park"]=++n;
    string A,B;int t;
    memset(G,-1,sizeof(G));
    for(int i=1;i<=m;i++){
        cin>>A>>B>>t;
        if(f[A]==0)f[A]=++n;if(f[B]==0)f[B]=++n;
        Add(f[A],f[B],t);
        if(G[f[A]][f[B]]==-1)G[f[A]][f[B]]=G[f[B]][f[A]]=t;
        else G[f[A]][f[B]]=G[f[B]][f[A]]=min(t,G[f[A]][f[B]]);
    }
    scanf("%d",&k);
    Kur();memset(mt,127/3,sizeof(mt));
    for(int i=2;i<=n;i++){
        if(G[1][i]!=-1){
            int r=find(i);
            if(G[1][i]<mt[r]){
                mt[r]=G[1][i];
                wh[r]=i;
            }
        }
    }
    for(int i=2;i<=n;i++)
        if(mt[i]!=mt[0]){
            sum++;ans+=G[1][wh[i]];
            vis[1][wh[i]]=vis[wh[i]][1]=1;
        }
    //得到最小sum度树
    for(int i=sum+1;i<=k;i++){
        dp[1].t=-1;
        for(int j=2;j<=n;j++){
            if(vis[1][j])dp[i].t=-1;
            else dp[i].t=0;
        }
        Dfs(1,-1);
        int pos,mii=1e9;
        for(int j=2;j<=n;j++){
            if(G[1][j]==-1)continue;
            if(mii>G[1][j]-dp[j].t){
                pos=j;mii=G[1][j]-dp[j].t;
            }
        }
        if(mii>=0)break;
        vis[1][pos]=vis[pos][1]=1;
        vis[dp[pos].u][dp[pos].v]=0;
        vis[dp[pos].v][dp[pos].u]=0;
        ans+=mii;
    }
    printf("Total miles driven: %d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/yanlifneg/p/9384664.html

时间: 2024-10-08 23:48:12

K度限制MST poj 1639的相关文章

K - The Unique MST - poj 1679

题目的意思已经说明了一切,次小生成树... ************************************************************************************ #include<algorithm>#include<stdio.h>#include<string.h>#include<queue>using namespace std; const int maxn = 105;const int oo 

poj 1639 Picnic Planning 度限制mst

https://vjudge.net/problem/POJ-1639 题意: 有一群人,他们要去某一个地方,每个车可以装无数个人,给出了n条路,包含的信息有路连接的地方,以及路的长度,路是双向的,但是终点只有一个,并且终点能停的车的数量是有限制的,问最少走的路是多少. 思路: 因为终点的停车的数量是有限制的,所以终点的度是有限制的,又因为这题可以用最小生成树解决,所以就是度限制最小生成树. 度限制最小生成树求解思想并不复杂,首先我们把有度限制的点给忽略,然后给每一个连通分量求最小生成树,最后把

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

[题意] 有n个巨人要去Park聚会.巨人A和先到巨人B那里去,然后和巨人B一起去Park.B君是个土豪,他家的停车场很大,可以停很多车,但是Park的停车场是比较小.只能停k辆车.现在问你在这个限制条件下.巨人到达Park的最短距离. 如果把那个条件去掉.那么就是就是求最小生成树.加上那个条件其实就是求顶点度数限制为k的最小生成树. Input Input will consist of one problem instance. The first line will contain a s

最小k度限制生成树

[题目描述] 给你一个图,n个点,m条边,求一颗生成树满足如下条件: (1)结点1的度不超过k. (2)在(1)条件下所求生成树最小. [算法引入] 最小k度限制生成树,就是指有特殊的某一点的度不能超过k时的最小生成树. 如果T是G的一个生成树且dT(v0)=k,则称T为G的k度限制生成树. G中权值和最小的k度限制生成树称为G的最小k度生成树. [算法思想] 设特殊的那点为v0,先把v0删除,求出剩下连通图的所有最小生成树. 假如有m棵最小生成树,那么这些生成树必定要跟v0点相连. 也就是说这

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

这是最小度限制生成树的经典问题,题意就不说了 题目链接:http://poj.org/problem?id=1639 一般都是1个顶点的度有限制k,如果每个顶点的度都有限制,那么当前是NP难的. 为了解决这个题目,先把限制度数的点设为V0点,那么把这一点先除外,那么剩下的点都没有度数限制,所有先对他们进行分析,把他们求生成森林后,假设得到t个连通分量,所以为了生成一棵把v0包含在内的树,必须让v0的度数限制度数k>=t,如果<t,无解. 接下来k度中已经用掉了t度,如何求从t度到k度的最小生成

poj1639 Picnic Planning,K度限制生成树

题意: 矮人虽小却喜欢乘坐巨大的轿车,车大到可以装下无论多少矮人.某天,N(N≤20)个矮人打算到野外聚餐.为了集中到聚餐地点,矮人A 要么开车到矮人B 家中,留下自己的轿车在矮人B 家,然后乘坐B 的轿车同行:要么直接开车到聚餐地点,并将车停放在聚餐地.虽然矮人的家很大,可以停放无数量轿车,但是聚餐地点却最多只能停放K 辆轿车.给你一张加权无向图,描述了N 个矮人的家和聚餐地点,求出所有矮人开车最短总路程. 单点K度限制最小生成树 算法步骤: 1.求出除去K度点的最小生成森林,设森林数为m 2

K - The Unique MST

K - The Unique MST #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct nond{ int x,y,z; }edge[101*101]; int T,N,M,x,y,z,fa[1000],num,ans[1000]; int tot,bns,k,answer=9999999; int cmp

[kuangbin带你飞]专题六 最小生成树 K - The Unique MST (判断最小生成树是否唯一)

K - The Unique MST 题目链接:https://vjudge.net/contest/66965#problem/K 题目: 给定连接的无向图,告诉它的最小生成树是否唯一. 定义1(生成树):考虑连通的无向图G =(V,E). G的生成树是G的子图,比如T =(V',E'),具有以下属性:    1. V'= V.    2.T是连接的和非循环的. 定义2(最小生成树):考虑边加权,连通,无向图G =(V,E). G的最小生成树T =(V,E')是总成本最小的生成树. T的总成本

(最大k度限制生成树)POJ 1639 - Picnic Planning

题意: 给一个无向带权图,图上有不超过20个人和1个公园,现在这些人想到公园去集合,他们可以直接去公园也可以,和其他人一起坐车去公园(假设他们的车容量无限),但是这个公园停车场只有k个位置,现在要求他们到达公园所需要的总花费. 分析: 乍一看是最小生成树,但是停车场只有k个位置,所以就限定了公园节点只能最多连k个人,也就是说有一个点的度数是给定了的. 想了很久,第一感觉就是想其他生成树那样,肯定要把边删去,从环中选择更优解, 按套路来说. 但是想了很久不知道怎么处理. 不过,看到题目只有20个人