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

 

时间:2011.6.1 19:58

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

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

思路:最小限制度生成树,是指在无向图里找一颗最小生成树,使给定点V0的度数<=k;

步骤:1.先求出最小m度限制生成树:将所有与Park连接的边去掉,得到一个或多个连通分量,各自求其最小生成树。当求出一个最小生成树T时,挑其中一个与Park最近的点,作为T的根,并以他为起点,求T上其他点的father节点。

        2.1,求m+1度限制生成树:先做处理,求出best[]数组,即比如best[3]=2,3Park路径上的最大的边权由2father[2]构成。之后,寻找一点x,使得g[source][x]-g[best[x]][father[bext[x]]]的和最小,并把边{best[x],father[best[x]]}去掉。

        3.当为K度限制生成树时,停止。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#define N 30
#define INF (1 << 30)
using namespace std;
 
int n, k, s, idx;
int vis[N], dis[N], f[N], pre[N], mark[N], best[N];
int g[N][N], edg[N][N];
map<string, int> q;
 
int dfs(int x)
{
    int i;
    for (i = 1; i <= idx; i++)
    {
        if (edg[i][x] && mark[i])
        {
            f[i] = x;
            mark[i] = 0;
            dfs(i);         
        }
    }
    return 1;
}
 
int prim(int x)
{
    int i, j, key, mini, sum = 0, root = -1;
    for (i = 1; i <= idx; i++)
    {
       dis[i] = g[x][i];
       pre[i] = x;
    }
    //pre[x] = s;
    memset(mark, 0, sizeof(mark));
    vis[x] = 1;
    mark[x] = 1;
    while (1)
    {
        mini = INF;
        key = -1;
        for (i = 1; i <= idx; i++)
        {
            if (! vis[i] && ! mark[i] && dis[i] < mini)
            {
                mini = dis[i];
                key = i; 
            }
        } 
        if (key == -1) break;
        vis[key] = 1;
        mark[key] = 1;
        edg[pre[key]][key] = edg[key][pre[key]] = 1;
        sum += dis[key];
        for (i = 1; i <= idx; i++)
        {
            if (! vis[i] && ! mark[i] && g[key][i] < dis[i])
            {
                dis[i] = g[key][i];
                pre[i] = key; 
            }
        }
    }
    mini = INF;
    for (i = 1; i <= idx; i++)
    {
        if (mark[i] && g[s][i] < mini)
        {
            mini = g[s][i];
            root = i;       
        }
    }
    mark[root] = 0;
    dfs(root);
    f[root] = s;
    return sum + mini;
}
 
int find_best(int x)
{
    int tmp;
    if (f[x] == s) return -1;
    if (best[x] != -1) return best[x];
    tmp = find_best(f[x]);
    if (tmp != -1 && g[f[tmp]][tmp] > g[f[x]][x])
        best[x] = tmp;
    else
        best[x] = x;
    return best[x];
}
 
int solve()
{
    int i, j, m = 0, mst = 0, minadd, ax, bx, tmp, change;
    memset(vis, 0, sizeof(vis));
    memset(f, -1, sizeof(f));
    memset(edg, 0, sizeof(edg));
    vis[s] = 1;
    for (i = 1; i <= idx; i++)
    {
        if (! vis[i])
        {
            mst += prim(i);
            m++; 
        }
    }
    for (i = m + 1; i <= k; i++)
    {
        memset(best, -1, sizeof(best));
        for (j = 1; j <= idx; j++)
        {
            if (best[j] == -1 && f[j] != s)
                find_best(j);
        }
        minadd = INF;
        for (j = 1; j <= idx; j++)
        {
            if (g[s][j] != INF && f[j] != s)
            {
                ax = best[j];
                bx = f[ax];
                tmp = g[s][j] - g[bx][ax];
                if (tmp < minadd)
                {
                    minadd = tmp;
                    change = j;   
                }       
            }
        }
        if (minadd >= 0) break;
        mst += minadd;
        ax = best[change];
        bx = f[ax];
        g[ax][bx] = g[bx][ax] = INF;
        f[ax] = bx = s;
        g[ax][bx] = g[bx][ax] = g[s][change];
        g[s][change] = g[change][s] = INF;
    }
    return mst;
}
 
int main()
{
    int i, j, d, t1, t2, mst;
    string s1, s2;
    scanf("%d", &n);
    for (i = 1; i <= N - 2; i++)
    {
        for (j = 1; j <= N - 2; j++)
            g[i][j] = INF;
    }
    idx = 1;
    q["Park"] = idx;
    while (n--)
    {
        cin >> s1 >> s2;
        scanf("%d", &d);
        if (q.find(s1) == q.end())
            t1 = q[s1] = ++idx;
        else t1 = q[s1];
        if (q.find(s2) == q.end())
            t2 = q[s2] = ++idx;
        else t2 = q[s2];    
        if (d < g[t1][t2])
            g[t1][t2] = g[t2][t1] = d;
    }
    scanf("%d", &k);
    s = 1;
    mst = solve();
    printf("Total miles driven: %d/n", mst);
    system("pause");
    return 0;
}


     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值