poj 1639 Picnic Planning k限制生成树问题

本文深入探讨了K度限制生成树问题,通过实例分析和代码实现,详细解释了解决此类问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:有一群兄弟去野餐,可以自己开车到目的地,或者开车到A的家里,然后和A一起去目的地。但目的地的停车场不一定容得下,如果每个人都自己开车去的话。所以这对连接到Park的边数有个限制。求他们总路径的最小值。

本体是一道k度限制生成树问题,可以参看资料:

http://wenku.baidu.com/view/70ef0e00eff9aef8941e06db.html

看后结合代码理解这种题目:当时参考了别人的代码

/*
最小k限制最小生成树;


*/


#include<iostream>
#include<cstdio>
#include <cstring>
#include <map>
#include<string>


using namespace std;


#define inf (1<<30)
#define M 30
int pre[M];
int g[M][M];
int link[M][M];
int vist[M];
map<string,int>name;


struct node {


    int u, v, len;
    node(){}
    node(int u, int v, int len):u(u),v(v),len(len){}


}point[M];


int k;
int root;
int ans;
int n, m;


void init(){


    int len;
    int u, v;
    ans = 0;
    char s1[20], s2[20];
    memset(g, 0x3f, sizeof(g));
    memset(vist, 0, sizeof(vist));
    memset(link, 0, sizeof(link));


    map<string, int >::iterator it1, it2;  //map的应用很好的解决了读入问题;
     name.clear();
    name["Park"] = 0;
    n = 1;
    for(int i = 0; i < m; i++){


        scanf("%s%s%d", s1, s2, &len);


        it1 = name.find(s1);
        it2 = name.find(s2);
        if(it1 != name.end()) u = it1->second;
        else {


            name[s1] = n;
            u = n++;
        }
        if(it2 != name.end()) v = it2->second;
        else {


            name[s2] = n;
            v = n++;
        }
        if(g[u][v] > len)
        g[u][v] = g[v][u] = len;
    }
//    for(int i = 0; i < n; i++)
//    for(int j= 0; j < n; j++){
//
//        printf("%d  %d  %d\n", i, j, g[i][j]);
//    }
    scanf("%d", &k);
}


void prime(int u){


    int dis[M];
    int minn = inf;
    int index = -1;
    vist[u] = 1;
    memset(pre, -1, sizeof(pre));
    for(int i = 1; i < n; i++){


        dis[i] = g[u][i];
        pre[i] = u;
    }


    // dis[u] = 0;
     while(1){


        minn = inf;
        index = -1;
        for(int i = 1; i < n; i++){


            if(!vist[i] && dis[i] < minn){


                minn = dis[i];
                index = i;
            }
        }
        if(index == -1)
            break;
        link[pre[index]][index] = link[index][pre[index]] = 1;
        vist[index] = 1;
        ans += dis[index];
        if(g[0][root] > g[0][index])
            root = index;


        for(int i = 1; i < n; i++){


            if(!vist[i] && dis[i] > g[index][i]){


                dis[i] = g[index][i];
                pre[i] = index;
            }
        }


     }


}


void dfs(int cur, int score, int u, int v){   //cur 当前点, score当前点的前驱,存在最长边的两个点。


    for(int i = 1; i < n; i++){


        if(i != score && link[cur][i]){   //不是还回边或不在最小生成树中的边。


            if(score == -1 || g[cur][i] >= g[u][v]){


                point[i] = node(cur, i, g[cur][i]);
                dfs(i, cur, cur, i);


            }else {


                point[i] = node(u, v, g[u][v]);
                dfs(i, cur, u, v);
            }
        }
    }
}


void work(){


    for(int i = 1; i < n; i++){


        if(vist[i]) continue;
        k--;
        root = i;
        prime(i);
        ans += g[0][root];
        link[0][root] = link[root][0] = 1;


        dfs(root, -1, -1, -1);
    }
    while(k--){


        int c= 0, index;
        for(int i = 1; i < n; i++){


            if(link[0][i] || g[0][i] == inf) continue;


            if(g[0][i] - point[i].len < c){


                c = g[0][i] - point[i].len;
                index = i;
            }
        }
        if(c == 0)
            break;
        if(c < 0){


            link[point[index].u][point[index].v] = link[point[index].v][point[index].u] = 0;
            link[0][index] = link[index][0] = 1;
            ans += c;
            dfs(index, -1, -1, -1);
        }
    }
    printf("Total miles driven: %d\n", ans);
}


int main()
{


    while(scanf("%d", &m) != EOF){


        init();
        work();
    }


    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值