zoukankan      html  css  js  c++  java
  • 最小度限制生成树模板

    #include<iostream>
    #include<algorithm>
    #include<string>
    #include<map>
    #include<stdio.h>
    #include<cstring>
    
    using namespace std;
    
    int const oo = 100000000;
    int cost[103][103]; 			// 花费=边 
    int used[103][103]; 			// 表示这条边是否在生成树中 
    int father[103]; 				// 生成树中点的 
    int maxlen[103]; 				// 表示i点到根的路径上除了与根直接相连的边外,边权最大的边的边权。
    int vis[103]; 					// 标记 
    int d[103];    					// 求最小生成树时的离最小生成树的代价 
    int AnsMst; 					// 当前m度生成树的代价 
    int N, degree, lim; 			// degree表示最小限度,lim表示限度值 
    int g[103][103]; 				// 生成树中的儿子关系,正向表。 
    map<string, int> mat;
    
     
    
    void MST(int S) 
    { // 求从S点开始的最小生成树 
        while (1) 
    	{
            int K = -1;
            for (int i = 1; i <= N; i++) 
    		{
                if (!vis[i] && d[i] != oo && (K == -1 || d[K] > d[i])) K = i;
            }
            if (K == -1) break;
            vis[K] = 1;
            AnsMst += d[K];
            g[father[K]][++g[father[K]][0]] = K; // 记录儿子 
            if (d[K] != 0)
    			maxlen[K] = max(maxlen[father[K]], d[K]); // 算边权最大的边 
            used[K][father[K]] = used[father[K]][K] = 1; // 标记边在生成树中 
            for (int i = 1; i <= N; i++) 
    		{
                if (!vis[i] && cost[K][i] < d[i]) 
    			{
                    father[i] = K;
                    d[i] = cost[K][i];
                }
            }
        }
    }
    void Build()
     {
        for (int i = 1; i <= N; i++) father[i] = i;
        for (int i = 1; i <= N; i++) d[i] = oo;
        for (int i = 1; i <= N; i++)
    		for (int j = 1; j <= N; j++)
    			used[i][j] = 0; // 所有的边都在生成树外 
        for (int i = 1; i <= N; i++) g[i][0] = 0; 								  // 儿子树全为0 
        for (int i = 1; i <= N; i++) vis[i] = 0; 								  // 标记清空 
        vis[1] = 1;
        degree = 0;
        maxlen[1] = -oo; // 根的maxlen为-oo 
        AnsMst = 0; // 开始时生成树的代价为0 
        while (1) 
    	{
            int K = -1;
            for (int i = 1; i <= N; i++)
    		{
                if (!vis[i] && (K == -1 || cost[1][i] < cost[1][K])) K = i; // 找一条边权最小的和跟相连的点开始做最小生成树 
            }
            if (K == -1) break;
            father[K] = 1; // father 为 1 
            maxlen[K] = -oo; // maxlen[k]=-oo
            d[K] = 0;
            degree++; // 联通分支个数加1 
            AnsMst += cost[1][K]; // 生成树代价增加
            MST(K);
        }
    }
    void Init()
    { // 开始的输入处理 
        mat.clear();
        mat["Park"] = 1;
        N = 1;
        int M;
        scanf("%d", &M);
        for (int i = 1; i <= 30; i++) 
    	{
            for (int j = 1; j <= 30; j++) cost[i][j] = oo;
        }
        while (M--) 
    	{
            string a, b;
            int c;
            cin >> a >> b >> c;
            int ida, idb;
            if (mat.find(a) == mat.end()) mat[a] = ++N, ida = N;
            else ida = mat[a];
            if (mat.find(b) == mat.end()) mat[b] = ++N, idb = N;
            else idb = mat[b];
            cost[ida][idb] = cost[idb][ida] = c;
        }
        scanf("%d", &lim);
    }
    
    void Dfs(int nod, int fa) 
    { // 更新维护maxlen和生成树中的父子关系 
        father[nod] = fa;
        vis[nod]=1;
        if (fa == 1) maxlen[nod] = -oo;
        else maxlen[nod] = max(maxlen[fa], cost[nod][fa]);
        for (int i = 1; i <= g[nod][0]; i++)
            if (used[nod][g[nod][i]] && !vis[g[nod][i]]) Dfs(g[nod][i], nod);
    }
    
    void Solve() 
    {
        if (degree > lim) cout << "Error" << endl;
        int ans = AnsMst;
        while (degree < lim) 
    	{
            degree++;
            int id = -1;
            int delta = oo;
            for (int i = 1; i <= N; i++) 
    		{ // 找代价最小的进行扩张 
                if (cost[1][i] != oo && !used[1][i]) 
    			{
                    if (id == -1) 
    				{
                        id = i;
                        delta = cost[1][i] - maxlen[i];
                        continue;
                    }
                    if (cost[1][i] - maxlen[i] < delta) 
    				{
                        id = i;
                        delta = cost[1][i] - maxlen[i];
                    }
                }
            }
            if (id == -1) break;
            AnsMst += delta;   // 加上delta值 
            ans = min(ans, AnsMst);
            int Len = maxlen[id];
            used[1][id] = used[id][1] = 1; // 表示边被加入到当前的生成树中 
            g[1][++g[1][0]] = id; // 表示根多了一个儿子 
            while (cost[id][father[id]] != Len) 
    		{ // 找最大的边,并顺路维护儿子关系 
                int fa = father[id];
                g[id][++g[id][0]] = fa;
                id = fa;
            }
            used[id][father[id]] = used[father[id]][id] = 0; // 标记边被删去 
            for (int i = 1; i <= N; i++) vis[i]=0;
            Dfs(1, 1); // 维护 
        }
        printf("Total miles driven: %d
    ", ans);
    }
    int main() {
        Init();
        Build();
        Solve();
        return 0;
    }
    

      

  • 相关阅读:
    Codeforces 1237D. Balanced Playlist
    Codeforces 1237C2. Balanced Removals (Harder)
    使用excel计算指数平滑和移动平均
    HP滤波原理浅学
    第二章平稳时间序列模型——ACF和PACF和样本ACF/PACF
    第二章平稳时间序列模型——AR(p),MA(q),ARMA(p,q)模型及其平稳性
    第一章时间序列基础——差分方程和求解(二)
    R中的par()函数的参数
    你真的懂了R中的stem函数是如何绘制茎叶图的么?
    关于R中的mode()和class()的区别
  • 原文地址:https://www.cnblogs.com/LUO257316/p/3257663.html
Copyright © 2011-2022 走看看