1. 程式人生 > >poj1639,uva1537,uvalive2099,scu1622,fzu1761 Picnic Planning (最小限制生成樹)

poj1639,uva1537,uvalive2099,scu1622,fzu1761 Picnic Planning (最小限制生成樹)

during hal {} rri 細節 xxx 找到 cred eth

Picnic Planning

Time Limit: 5000MS Memory Limit: 10000K
Total Submissions: 10742 Accepted: 3885

Description

The Contortion Brothers are a famous set of circus clowns, known worldwide for their incredible ability to cram an unlimited number of themselves into even the smallest vehicle. During the off-season, the brothers like to get together for an Annual Contortionists Meeting at a local park. However, the brothers are not only tight with regard to cramped quarters, but with money as well, so they try to find the way to get everyone to the party which minimizes the number of miles put on everyone‘s cars (thus saving gas, wear and tear, etc.). To this end they are willing to cram themselves into as few cars as necessary to minimize the total number of miles put on all their cars together. This often results in many brothers driving to one brother‘s house, leaving all but one car there and piling into the remaining one. There is a constraint at the park, however: the parking lot at the picnic site can only hold a limited number of cars, so that must be factored into the overall miserly calculation. Also, due to an entrance fee to the park, once any brother‘s car arrives at the park it is there to stay; he will not drop off his passengers and then leave to pick up other brothers. Now for your average circus clan, solving this problem is a challenge, so it is left to you to write a program to solve their milage minimization problem.

Input

Input will consist of one problem instance. The first line will contain a single integer n indicating the number of highway connections between brothers or between brothers and the park. The next n lines will contain one connection per line, of the form name1 name2 dist, where name1 and name2 are either the names of two brothers or the word Park and a brother‘s name (in either order), and dist is the integer distance between them. These roads will all be 2-way roads, and dist will always be positive.The maximum number of brothers will be 20 and the maximumlength of any name will be 10 characters.Following these n lines will be one final line containing an integer s which specifies the number of cars which can fit in the parking lot of the picnic site. You may assume that there is a path from every brother‘s house to the park and that a solution exists for each problem instance.

Output

Output should consist of one line of the form
Total miles driven: xxx
where xxx is the total number of miles driven by all the brothers‘ cars.

Sample Input

10
Alphonzo Bernardo 32
Alphonzo Park 57
Alphonzo Eduardo 43
Bernardo Park 19
Bernardo Clemenzi 82
Clemenzi Park 65
Clemenzi Herb 90
Clemenzi Eduardo 109
Park Herb 24
Herb Eduardo 79
3

Sample Output

Total miles driven: 183

題意:

要求做一個最小生成樹,限制條件:給定其中一個點限制其的度不超過 k (最小 k 度限制生成樹)。

思路:

第一步,設被限制度數的節點為 v0 ,則在去除 v0 的情況下做最小生成樹,可能得到若幹個最小生成樹(設有 m 棵樹);容易想到,這寫樹必須通過 v0 來連接成一顆樹。

第二步,從 v0 引出 m 條邊分別連向 m 棵樹,則此時得到一個最小 m 度限制生成樹,若給定的 k 小於 m 則說明這不是連通圖,無法做生成樹。

第三步,最多找出 k-m 條 v0 的邊去替換樹上現有的邊;當然,替換必須使樹變小才合法。這一步是比較麻煩的,並且若直接枚舉的話時間復雜度也較高。每次使用動態規劃找出一條貢獻最大的邊,並替換進樹中。直到找齊 k-m 條邊、或無法找到合法邊是停止。此時得到的就是最小 k 度限制生成樹了。

總結:

思路如上十分清晰,可實現起來細節太多了,比較坑的是同一道題不能在不同的OJ AC。在多次調試之後我的代碼總算征服了poj、uva、uvalive、scu,但 fzu 卻遲遲不能AC。在縱觀其他大佬的題解後,發現我的代碼已經算強的了....

此題需要註意的是:輸入是兩點之間可能存在多條邊,需要保留最小的邊。

代碼:

#include<iostream>
#include<map>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstdio>
#define READFILE freopen("D:\\in.txt","r",stdin);
#define INF 1e9+7
using namespace std;

class Edge
{
public:
    int u, v, w;
    Edge(int a=0, int b=0, int c=0):u(a), v(b), w(c) {}
};

map<string, int> mp;
vector<Edge> edges;
Edge dp[105];
int m, n, k, md, grap[105][105], fa[105], mst[105][105], ans=0;

bool cmp(Edge a, Edge b)
{
    return a.w<b.w;
}

void Init()
{
    memset(grap, -1, sizeof(grap));//-1不可達
    memset(mst, 0, sizeof(mst));
    mp.clear();
    edges.clear();
    n=1, md=0, ans=0, k=0;
    int u, v, w;
    mp["Park"]=1;

    string name1, name2;
    cin>>m;
    for(int i=0; i<m; ++i)
    {
        cin>>name1>>name2>>w;
        if(mp.find(name1)==mp.end())
            mp[name1]=n++;
        if(mp.find(name2)==mp.end())
            mp[name2]=n++;
        u=mp[name1], v=mp[name2];
        edges.push_back(Edge(u, v, w));
        if(grap[u][v]==-1)
            grap[u][v]=grap[v][u]=w;
        else
            grap[u][v]=grap[v][u]=min(grap[u][v], w);
    }
    cin>>k;
}

int Find(int x)
{
    if(fa[x]!=x)
        return fa[x]=Find(fa[x]);
    return x;
}

void Union(int a, int b)
{
    int x=Find(a);
    int y=Find(b);
    if(x!=y)
        fa[x]=y;
}

int Kruskal()//去除限制點生成md棵最小生成樹
{
    int res=0;
    sort(edges.begin(), edges.end(), cmp);
    for(int i=0; i<=n; ++i)
        fa[i]=i;
    for(int i=0; i<edges.size(); ++i)
    {
        Edge& e=edges[i];
        if(e.u==1 || e.v==1 || Find(e.u)==Find(e.v)) continue;
        Union(e.u, e.v);
        mst[e.u][e.v]=mst[e.v][e.u]=grap[e.u][e.v];
        res+=grap[e.u][e.v];
    }
    return res;
}

int mmst()//生成最小md度限制生成樹
{
    int minw[25], minv[25], res=0;
    for(int i=0; i<=n; ++i) minw[i]=INF;
    for(int i=2; i<=n; ++i)
        if(grap[1][i]!=-1)
        {
            int x=Find(i);
            if(minw[x] > grap[1][i])
            {
                minw[x]=grap[1][i];
                minv[x]=i;
            }
        }
    for(int i=1; i<=n; ++i)
        if(minw[i]!=INF)
        {
            md++;
            mst[1][minv[i]]=mst[minv[i]][1]=1;
            res+=grap[1][minv[i]];
        }
    return res;
}

void dfs(int x,int fa)
{
    for(int i=2; i<=n; i++)
        if(mst[x][i] && i!=fa)
        {
            if(dp[i].w==-1)
            {
                if(grap[x][i]<dp[x].w)
                {
                    dp[i].u=dp[x].u;
                    dp[i].v=dp[x].v;
                    dp[i].w=dp[x].w;
                }
                else
                    dp[i].u=x,dp[i].v=i,dp[i].w=grap[x][i];
            }
            dfs(i,x);
        }
}
int mkst()
{
    int res=0;
    for(int i=md+1; i<=k; i++)
    {
        for(int j=0; j<=n; ++j)
            dp[j].w=-1;
        dp[1].w=-INF;
        for(int j=2; j<=n; j++)
            if(mst[1][j])
                dp[j].w=-INF;
        dfs(1,-1);
        int t=0,minn=INF;
        for(int j=2; j<=n; j++)
            if(grap[1][j]!=-1&&grap[1][j]-dp[j].w<minn)
            {
                minn=grap[1][j]-dp[j].w;
                t=j;
            }
        if(minn>=0)
            break;
        mst[1][t]=mst[t][1]=1;
        int x=dp[t].u,y=dp[t].v;
        mst[x][y]=mst[y][x]=0;
        res+=minn;
    }
    return res;
}

int main()
{
    //READFILE
    int t;
    t=1;//有的oj多組數據此處改為cin>>t即可
    while(t--)
    {
        Init();
        int ans1=Kruskal();
        int ans2=mmst();
        int ans3=mkst();
        ans=ans1+ans2+ans3;
        cout<<"Total miles driven: "<<ans<<endl;
        if(t)cout<<endl;
    }
    return 0;
}

poj1639,uva1537,uvalive2099,scu1622,fzu1761 Picnic Planning (最小限制生成樹)