现在的位置: 首页 > 算法 > 正文

poj1639 Picnic Planning

2019年09月22日 算法 ⁄ 共 3094字 ⁄ 字号 评论关闭
#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <memory.h>

using namespace std;

/*
 * poj1639 AC 
 * K度最小生成树
 * 1. 求出除去V0,其他每个森林的最小生成树(除去V0后,其他的点不一定都是连通的)。
 * 2. 在每个森林中找出与V0距离最近的点,并与V0相连(此时即为一棵生成树,这棵
 *    生成树的根结点为V0,即在与V0相连时,要修改前驱数组pre[])。
 * 3. 循环 (度数 – 森林数)次,每次找到g[0][i] – MV[i]最小的i结点,其中MV[i]
 *    为Vi到V0的路径上不与V0相连的边的最大权值。
 *    如果g[0][i] – MV[i] >= 0说明已经是最优解了,退出。
 *    否则加入g[0][i]这条边,删去Vi到V0的路径上不与V0相连的最大权值的边。
 *
 * 如何快速找到Vi到V0的路径上不与V0相连的边的最大权值?
 * MV[x] = max(MV[father],edge[i].c) (edge[i]为x到father的边,递推可得)
 * */

int N,S,T;
map<string,int> hash;
struct EDGE
{
    int u,v,c,nm;
}edge[1000];
int head[25],next[1000],tot,goal;

struct cmp
{
    bool operator()(const EDGE &t1,const EDGE &t2)
    {
        return t1.c>t2.c;
    }
};

void addedge(int x,int y,int val)
{
    edge[tot].u = x,edge[tot].v = y,edge[tot].c = val,edge[tot].nm = tot;
    next[tot] = head[x],head[x] = tot++;
}

priority_queue<EDGE,vector<EDGE>,cmp> heap;
bool vis[25],sel_e[1000];

int solve(int x,int TT)
{
    int E,nn,SUM;

    while(!heap.empty()) heap.pop();
    for(int i=head[x];i!=-1;i=next[i])
        if(edge[i].v!=goal)
            heap.push(edge[i]);
    vis[x] = true,SUM = E = 0;
 
    while(E<TT-1)
    {
        EDGE e = heap.top();
        heap.pop();
        if(vis[e.v]) continue;

        sel_e[e.nm] = sel_e[e.nm^1] = true;
        E++,SUM += e.c;
        nn = e.v,vis[e.v] = true;

        for(int i=head[nn];i!=-1;i=next[i])
            if(edge[i].v!=goal && !vis[edge[i].v])
                heap.push(edge[i]);
    }
    return SUM;
}

int col[25],C;
int dfs(int x)
{
    col[x] = C;
    int ss = 1;
    for(int i=head[x];i!=-1;i=next[i])
        if(edge[i].v!=goal && !col[edge[i].v])
            ss += dfs(edge[i].v);
    return ss;
}

int MV[25],ne[25];
void dfs_V(int x,int f)
{
    for(int i=head[x];i!=-1;i=next[i])
        if(sel_e[i] && edge[i].v!=f && edge[i].v!=goal)
        {
            if(MV[x]>edge[i].c)
            {
                MV[edge[i].v] = MV[x];
                ne[edge[i].v] = ne[x];
            }else
            {
                MV[edge[i].v] = edge[i].c;
                ne[edge[i].v] = i;
            }
            dfs_V(edge[i].v,x);
        }
}

int main()
{
    scanf("%d",&N);
    char st[20],en[20];
    T = tot = goal = 0;
    memset(head,-1,sizeof(head));
    hash.clear();
    for(int i=1;i<=N;i++)
    {
        int k;
        scanf("%s%s%d",st,en,&k);
        if(!hash.count(st)) hash[st] = ++T;
        if(!hash.count(en)) hash[en] = ++T;
        if(!goal)
        {
            if(!strcmp(st,"Park")) goal = hash[st];
            if(!strcmp(en,"Park")) goal = hash[en];
        }
        addedge(hash[st],hash[en],k);
        addedge(hash[en],hash[st],k);
    }
    scanf("%d",&S);

    int ans = 0;
    C = 0;
    memset(vis,false,sizeof(vis));
    memset(col,0,sizeof(col));
    memset(sel_e,false,sizeof(sel_e));

    for(int i=1;i<=T;i++)
        if(i!=goal && !col[i])
            ++C,ans += solve(i,dfs(i));

    int mi[25],me[25];
    memset(mi,-1,sizeof(mi));
    for(int i=head[goal];i!=-1;i=next[i])
    {
       int k = edge[i].v;
       if(mi[col[k]]==-1 || edge[i].c<mi[col[k]])
       {
           mi[col[k]] = edge[i].c;
           me[col[k]] = i;
       }
    }

    for(int i=1;i<=C;i++)
        ans += mi[i],sel_e[me[i]] = sel_e[me[i]^1] = true;
    
    memset(MV,0,sizeof(MV));
    for(int i=head[goal];i!=-1;i=next[i])
        if(sel_e[i] && edge[i].v!=goal)
            dfs_V(edge[i].v,goal);

    for(int i=1;i<=S-C;i++)
    {
        int mm = 100000000,xx,ee,ww;
        for(int j=head[goal];j!=-1;j=next[j])
            if(!sel_e[j] && (mm==100000000 || mm>edge[j].c-MV[edge[j].v]))
            {
                mm = edge[j].c-MV[edge[j].v];
                xx = edge[j].v,ee = j,ww = ne[edge[j].v];
            }
        if(mm>=0) break;
        ans += mm;
        sel_e[ee] = sel_e[ee^1] = true;
        sel_e[ww] = sel_e[ww^1] = false;
        MV[xx] = 0;
        dfs_V(xx,goal);
    }

    printf("Total miles driven: %d\n",ans);
    return 0;
}

抱歉!评论已关闭.