POJ1639顶点度限制最小生成树

题目:http://poj.org/problem?id=1639

见汪汀的《最小生成树问题的拓展》。

大体是先忽略与根节点相连的边,做一遍kruscal,得到几个连通块和一个根节点;

然后根节点和每个连通块连一条边,当然是尽量小的,这时连的边就是根的最少度;

然后用增广的思路多给根连边,具体证明见论文;当最优的交换值也是负的时候break。

每次都要从根开始重弄dp值是因为要赋一遍初值。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>//
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
const int N=250;
const ll INF=0x7fffffff;
int n,m,K,s,fa[N],xnt,tmp[N],rd,rnt;
bool b[N][N];
ll f[N][N],d[N],ans;
map<string,int> mp;
struct Bh{
    int x,y;
    Bh(int a=0,int b=0):x(a),y(b) {}
}bh[N],r[N];
bool cmp(int a,int b){return f[s][a]<f[s][b];}
bool cmp2(Bh a,Bh b){return f[a.x][a.y]<f[b.x][b.y];}
int find(int a)
{
    if(fa[a]==a)return a;
    return fa[a]=find(fa[a]);
}
void dfs(int cur,int fa)
{
//    printf("(%d)",cur);
    for(int i=1;i<=n;i++)
        if(b[cur][i]&&i!=fa)
        {
            if(d[i]<d[cur])d[i]=d[cur],bh[i]=bh[cur];
            if(d[i]<f[cur][i])d[i]=f[cur][i],bh[i]=Bh(cur,i);
            dfs(i,cur);
        }
}
int main()
{
    scanf("%d",&m);
    memset(f,1,sizeof f);
    string x,y;ll z;
    for(int i=1;i<=m;i++)
    {
        cin>>x>>y>>z;//
        if(!mp[x])mp[x]=++n;if(!mp[y])mp[y]=++n;
        f[mp[x]][mp[y]]=f[mp[y]][mp[x]]=min(f[mp[x]][mp[y]],z);
        
    }
    s=mp["Park"];
    scanf("%d",&K);
    for(int i=1;i<=n;i++)
    {
        fa[i]=i;
        for(int j=i+1;j<=n;j++)
            if(f[i][j]<INF)r[++rnt]=Bh(i,j);
    }
    sort(r+1,r+rnt+1,cmp2);        //
    for(int u=1,i,j;u<=rnt;u++)
        if(find(i=r[u].x)!=find(j=r[u].y)&&i!=s&&j!=s)
        {
            fa[find(i)]=find(j);
            b[i][j]=b[j][i]=1;
        }
    for(int i=1;i<=n;i++)
        if(f[s][i]<INF&&i!=s)tmp[++xnt]=i;
    sort(tmp+1,tmp+n,cmp);
    for(int i=1,v;i<=n;i++)
        if(find(v=tmp[i])!=s)
        {
            fa[find(v)]=s;
            b[v][s]=b[s][v]=1;
            rd++;
        }
    memset(d,-2,sizeof d);
    dfs(s,0);
    for(;rd<=K;rd++)
    {
        ll mx=-INF;int u=0;
        for(int i=1,v;i<=xnt;i++)
            if(!b[v=tmp[i]][s]&&f[bh[v].x][bh[v].y]-f[s][v]>mx)
                mx=f[bh[v].x][bh[v].y]-f[s][v],u=v;
            if(mx<=0)break;//
            b[s][u]=b[u][s]=1;
            b[bh[u].x][bh[u].y]=b[bh[u].y][bh[u].x]=0;
            memset(d,-2,sizeof d);//
            dfs(s,0);
    }
    for(int i=1;i<n;i++)
        for(int j=i+1;j<=n;j++)
            ans+=b[i][j]?f[i][j]:0;
    printf("Total miles driven: %lld",ans);
    return 0;
}

 

posted on 2018-04-12 00:46  Narh  阅读(194)  评论(0编辑  收藏  举报

导航