poj1639最小度限制生成樹(kruscal+鄰接表)

一、.思路

設限制結點爲des.

 1. 求去掉des的最小生成樹,此時求出來的是最小生成森林

 2.添加des到各連通分量的邊,當然取最小的邊。

 3.此時得到m度的生成樹,我們要求的是小於等於k度的最小生成樹,此時我們可以用來調整的邊只有k-m條,

注意我們不一定要強制添加k-m條從des出發的邊,並刪除與其構成環的最大的邊,而是如果在可調整的範圍內(滿足度限制要求<=k)已經是最小的生成樹

就可以直接退出。

這裏給出算法的主過程,方便大家理解!

思路參考:國家集訓隊論文《最小生成樹問題的拓展》

代碼參考:http://www.cnblogs.com/ylfdrib/archive/2010/08/21/1805505.html

                    http://happylch21.blog.163.com/blog/static/16563975920113224491211/

int kDegreeMinTree()
    {
        int cost=0;
        cost+=kruscal();
        int m;
        cost+=mDegreeMinTree(m);
        cost+=expandToKDegree(k-m);
        return cost;
    }


二、.代碼


#include<cstdio>
#include<iostream>

using namespace std;
//   freopen("data.in","r",stdin);

#include<algorithm>
#include<cstring>
#define N 25
#define M N*N//double
#define MAX 1000000000
struct Edge
{
    int u,v,next;
    int w;
} edge[M];

bool cmp(const int &a,const int &b)
{
    return edge[a].w<edge[b].w;
}
struct Graph
{
    int index[M],len;
    int first[N];
    bool branch[M];
    int _V,_E,des;//!!
    int k;
    int father[N];//!!前後兩次的含義不一樣,第一次是作爲並查的頂點,第二次是作爲某一條邊的父邊
    int best[N];

    char brother[25][15];
    char t[15];

    void initial(int m)
    {
        _V=0;
        _E=0;
        memset(first,-1,sizeof(first));
    }
    int find()
    {
        for(int i=0; i<_V; i++)
        {
            if(strcmp(brother[i],t)==0)return i;
        }
        strcpy(brother[_V],t);//!!
        return _V++;
    }
    void createGraph(int m)
    {
        initial(m);

        while(m--)
        {
            scanf("%s",t);
            int u=find();
            scanf("%s",t);
            int v=find();
            int w;
            scanf("%d",&w);
            add(u,v,w);
            add(v,u,w);
        }

        for(int i=0; i<_V; i++)
        {
            if(strcmp("Park",brother[i])==0)
            {
                des=i;
                break;
            }
        }
        scanf("%d",&k);
    }

    void add(int u,int v,int w)
    {
        edge[_E].u=u;
        edge[_E].v=v;
        edge[_E].w=w;
        edge[_E].next=first[u];
        first[u]=_E;
        _E++;
    }

    int findx(int u)
    {
        if(father[u]==u)return u;
        else return father[u]=findx(father[u]);
    }
    void Union(int x,int y)
    {
        father[x]=father[y];
    }
    int kruscal()
    {
        int cost=0;
        len=_E>>1;
        for(int i=0; i<len; i++)index[i]=i<<1;
        sort(index,index+len,cmp);

        memset(branch,0,sizeof(branch));
        for(int i=0; i<_V; i++)father[i]=i;
        for(int i=0; i<len; i++)
        {
            int e=index[i],u=edge[e].u,v=edge[e].v;
            if(u==des||v==des)continue;
            int root1=findx(u),root2=findx(v);
            if(root1!=root2)
            {
                branch[e]=branch[e^1]=true;
                cost+=edge[e].w;
                Union(root1,root2);
            }
        }
        return cost;
    }

    int mDegreeMinTree(int &m)
    {
        m=0;
        int cost=0;
        while(1)
        {
            int minE=-1;
            for(int e=first[des]; e!=-1; e=edge[e].next)
            {
                int v=edge[e].v;
                int rootV=findx(v);
                if(rootV!=des)
                {
                    if(minE==-1||edge[minE].w>edge[e].w)minE=e;
                }
            }
            if(minE==-1)break;
            m++;
            cost+=edge[minE].w;
            branch[minE]=branch[minE^1]=true;
            Union(findx(edge[minE].v),des);//!!
        }
        return cost;
    }

    void calFather(int u)
    {
        for(int e=first[u]; e!=-1; e=edge[e].next)
        {
            if(branch[e])
            {
                father[edge[e].v]=e;
                branch[e]=branch[e^1]=false;
                calFather(edge[e].v);
                branch[e]=branch[e^1]=true;//!!恢復
            }
        }
    }
    void dfs(int u)
    {
        int fE=father[u],fP=edge[fE].u;
        if(fP!=des)
        {
            int e=best[fP];
            if(e==-1 || edge[fE].w>edge[e].w)best[u]=fE;
            else best[u]=e;
        }
        for(int e=first[u]; e!=-1; e=edge[e].next)
        {
            if(branch[e])
            {
                branch[e]=branch[e^1]=false;
                dfs(edge[e].v);
                branch[e]=branch[e^1]=true;
            }
        }
    }

    int expandToKDegree(int rest)
    {
        int cost=0;
        calFather(des);
        while(rest)
        {
            memset(best,-1,sizeof(best));

            for(int e=first[des]; e!=-1; e=edge[e].next)
            {
                int v=edge[e].v;
                if(edge[father[v]].u==des)dfs(v);//!!best[v]=-1;恆立
            }

            int minE=-1,minCost=MAX;
            for(int e=first[des]; e!=-1; e=edge[e].next)
            {
                if(!branch[e])
                {
                    int v=edge[e].v;
                    int curCost=edge[e].w-edge[best[v]].w;
                    if(curCost<0&&minCost>curCost)//!!
                    {
                        minCost=curCost;
                        minE=e;
                    }
                }
            }

            if(minE==-1)return cost;
            else
            {
                int v=edge[minE].v;
                int other=best[v];
                cost+=minCost;
                branch[minE]=branch[minE^1]=true;
                branch[other]=branch[other^1]=false;
                calFather(v);//!!
                rest--;
            }
        }
        return cost;
    }

    int kDegreeMinTree()
    {
        int cost=0;
        cost+=kruscal();
        int m;
        cost+=mDegreeMinTree(m);
        cost+=expandToKDegree(k-m);
        return cost;
    }
    void printTree()
    {
        for(int e=0; e<_E; e+=2)
        {
            if(branch[e])cout<<edge[e].u<<' '<<edge[e].v<<' '<<edge[e].w<<endl;
        }
        cout<<endl;
    }
    void printEdge(int *a,char *s)
    {
        printf("%s\n",s);
        for(int u=0; u<_V; u++)
        {
            cout<<u<<' '<<endl;
            int e=a[u];
            cout<<edge[e].u<<' '<<edge[e].v<<' '<<edge[e].w<<endl;
        }
        cout<<endl;
    }
} net;

int main()
{
    //  freopen("data.in","r",stdin);
    int m;
    cin>>m;
    net.createGraph(m);
    printf("Total miles driven: %d\n",net.kDegreeMinTree());
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章