最小度限制生成树(K度限制生成树)

例题 POJ 1639 Picnic Planning


  求最小度生成树,实质上是将一个V0点的最小度生成树展开的过程。

  1. 首先,求的除了V0点以外的所有子树的最小生成树,并且知道每棵子树到V0的最小边,以及是由哪个点延展过去的,于是,我们首先可以确定最小度生成树,假设此时的度是cnt。(子树个数)
  2. 然后就是展开的过程,对于每棵子树,我们找到最优的展开点,而且,要知道对于所有的最优展开的点只能往这棵最大K度生成树再放至多(K - cnt)个点,也就是可以拆出来(K - cnt)这么多个点。所以,每次都必须最贪心。
  3. 如何替换?就是将找到的最优替换点的原来的链接边(也就是它和它父亲结点链接的边)打开,然后呢V0去和对应的点链接,这个对应的点指的不是最优替换点,而是有和V0链接的那个点V,最优替换点是V到V0路径上的某个最长边对应的点。
  4. 于是,如果替换的价值为正值,那么就可以继续,因为这是保证最贪心的,如果小于等于0了,或者是已经取得到了K个点了,退出循环,结束算法。

推荐利用模拟的做法来模拟这个过程,没有模板,看作一道模拟题吧。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 22;
int N, M, K, root[maxN], Minn_Dis[maxN], Minn_ID[maxN], ans_MST, tree_num;
int fid(int x) { return x == root[x] ? x : root[x] = fid(root[x]); }
string s1, s2;
struct Graph
{
    int u, v, w;
    Graph(int a=0, int b=0, int c=0):u(a), v(b), w(c) {}
    friend bool operator < (Graph e1, Graph e2) { return e1.w < e2.w; }
} E[maxN * maxN];
vector<Graph> vt;
map<string, int> name;
struct Build_Graph
{
    int mp[maxN][maxN]; bool link[maxN][maxN];
    inline void _add(int u, int v, int w) { link[u][v] = link[v][u] = true; mp[u][v] = mp[v][u] = min(mp[u][v], w); }
    inline void _cut(int u, int v) { link[u][v] = link[v][u] = false; mp[u][v] = mp[v][u] = INF; }
    inline void init()
    {
        for(int i=1; i<=N; i++) for(int j=1; j<=N; j++) { link[i][j] = false; mp[i][j] = INF; }
    }
} Old;
inline void Kruskal()
{
    ans_MST = tree_num = 0;
    for(int i=1, fu, fv; i<=M; i++)
    {
        if(E[i].u == 1)
        {
            fv = fid(E[i].v);
            if(Minn_Dis[fv] > E[i].w) { Minn_Dis[fv] = E[i].w; Minn_ID[fv] = E[i].v; }
            vt.push_back(Graph(E[i].u, E[i].v, E[i].w));
        }
        else if(E[i].v == 1)
        {
            fu = fid(E[i].u);
            if(Minn_Dis[fu] > E[i].w) { Minn_Dis[fu] = E[i].w; Minn_ID[fu] = E[i].u; }
            vt.push_back(Graph(E[i].v, E[i].u, E[i].w));
        }
        else
        {
            fu = fid(E[i].u); fv = fid(E[i].v);
            if(fu ^ fv)
            {
                ans_MST += E[i].w;
                root[fu] = fv;
                if(Minn_Dis[fu] < Minn_Dis[fv]) { Minn_Dis[fv] = Minn_Dis[fu]; Minn_ID[fv] = Minn_ID[fu]; }
                Old._add(E[i].u, E[i].v, E[i].w);
            }
        }
    }
    for(int i=2; i<=N; i++) if(fid(i) == i)
    {
        ans_MST += Minn_Dis[i];
        tree_num++;
        Old._add(1, Minn_ID[i], Minn_Dis[i]);
    }
}
struct DP
{
    int id, fa, dis;
    DP(int a=0, int c=0, int b=0):id(a), fa(c), dis(b) {}
    friend bool operator < (DP e1, DP e2) { return e1.dis < e2.dis; }
} dp[maxN];
void dfs(int u, int fa)
{
    for(int i=2; i<=N; i++)
    {
        if(Old.link[u][i] && (i ^ fa))
        {
            dp[i] = max(DP(i, u, Old.mp[u][i]), dp[u]);
            dfs(i, u);
        }
    }
}
void solve()
{
    int len = (int)vt.size();
    for(int tims=tree_num, maxx_det, id; tims < K; tims++)
    {
        maxx_det = -INF; id = -1;
        for(int i=0; i<len; i++)
        {
            if(dp[vt[i].v].dis - vt[i].w > maxx_det && !Old.link[1][vt[i].v])
            {
                maxx_det = dp[vt[i].v].dis - vt[i].w;
                id = i;
            }
        }
        if(maxx_det <= 0) break;
        ans_MST -= maxx_det;
        Old._add(1, vt[id].v, vt[id].w);
        Old._cut(dp[vt[id].v].id, dp[vt[id].v].fa);
        dfs(1, 0);
    }
}
inline void init()
{
    Old.init(); dp[1] = DP(1, 0, 0); vt.clear();
    for(int i=1; i<=N; i++)
    {
        root[i] = i; Minn_ID[i] = i;
        Minn_Dis[i] = INF;
    }
}
int main()
{
    scanf("%d", &M); name["Park"] = N = 1;
    for(int i=1, val; i<=M; i++)
    {
        cin >> s1 >> s2; scanf("%d", &val);
        if(!name[s1]) name[s1] = ++N;
        if(!name[s2]) name[s2] = ++N;
        E[i] = Graph(name[s1], name[s2], val);
    }
    sort(E + 1, E + M + 1);
    init();
    scanf("%d", &K);
    Kruskal();  //现在有tree_num个子树,合并,最多K个
    dfs(1, 0);
    solve();
    printf("Total miles driven: %d\n", ans_MST);
    return 0;
}
发布了797 篇原创文章 · 获赞 958 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/104401625