• poj1639顶点度限制生成树


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

    对根的度数有限制的最小生成树;

    先忽略根,跑最小生成树,得到几个连通块,再一一与根连上;

    然后在限制内用根连出去的边来使生成树更小,这需要枚举边以及用dp维护树上边的dfs序之前最大的一个;

    此题用邻接矩阵比较方便。

    改了一晚上,终于发现是混淆了n和cnt,cnt才是点数。

    邻接表失败版:

    #include<iostream>
    #include<cstdio>
    #include<map>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,m,head[25],ct=1,cnt,ed,fa[25],cost,reg;
    char s1[15],s2[15];
    map<string,int>mp;
    struct N{
        int to,next,w;
        N(int t=0,int n=0,int ww=0):to(t),next(n),w(ww) {}
    }edge[50],e[25];
    struct NN{
        int v,bh;
    }dp[25];
    bool use[50],use2[50],lk[25],vis[25];
    bool cmp(N x,N y){return x.w<y.w;}
    int find(int x)
    {
        if(x==fa[x])return x;
        return fa[x]=find(fa[x]);
    }
    void kruskal()
    {
        sort(edge+2,edge+ct+1,cmp);
        for(int i=1;i<=n;i++)fa[i]=i;
        for(int i=2;i<=ct;i+=2)
        {
            int u=edge[i].to;
            int v=edge[i^1].to;
            if(find(u)!=find(v))
            {
                cost+=edge[i].w;
                fa[find(u)]=find(v);
                use[i]=1;
                use[i^1]=1;
            }
        }
    }
    void dfs(int x)
    {
        vis[x]=1;
        for(int i=head[x];i;i=edge[i].next)
        {
            int u=edge[i].to;
            if(!use[i]||vis[u])continue;
    //        printf("u=%d
    ",u);
    //        printf("x=%d——u=%d
    ",x,u);
            if(dp[x].v>edge[i].w)
            {
                dp[u].v=dp[x].v;
                dp[u].bh=dp[x].bh;
            }
            else
            {
    //            printf("u=%d x=%d
    ",u,x);
                dp[u].v=edge[i].w;
    //            printf("dp[%d].v=%d
    ",u,dp[u].v);
                dp[u].bh=i;
            }
            dfs(u);
        }
    }
    void add(int x,int y,int z)
    {
        ct++;
        edge[ct].to=y;
        edge[ct].next=head[x];
        edge[ct].w=z;
        head[x]=ct;
    }
    int main()
    {
        scanf("%d",&n);
        mp["Park"]=++cnt;
        for(int i=1;i<=n;i++)
        {
            int x;
            scanf("%s %s",&s1,&s2);
            scanf("%d",&x);
            if(!mp[s1])mp[s1]=++cnt;
            if(!mp[s2])mp[s2]=++cnt;
            if(mp[s1]==1)
            {
                e[++ed].to=mp[s2];
                e[ed].w=x;
                continue;
            }
            if(mp[s2]==1)
            {
                e[++ed].to=mp[s1];
                e[ed].w=x;
                continue;
            }
    //        edge[++ct]=(mp[s2],head[mp[s1]],x);head[mp[s1]]=ct;
    //        edge[++ct]=(mp[s1],head[mp[s2]],x);head[mp[s2]]=ct;
            add(mp[s2],mp[s1],x);
            add(mp[s1],mp[s2],x);
        }
    //    for(int i=2;i<=ct;i++)
    //        printf("w=%d to=%d
    ",edge[i].w,edge[i].to);
        scanf("%d",&m);
        kruskal();
        sort(e+1,e+ed+1,cmp);
        for(int i=1;i<=ed;i++)
        {
            int u=e[i].to;
            if(!lk[find(u)])
            {
                cost+=e[i].w;
                lk[find(u)]=1;
                use2[i]=1;
                reg++;
            }
        }
        vis[1]=1;
        for(int i=1;i<=ed;i++)
        {
            if(!use2[i])continue;
            dp[e[i].to].v=-1;
            dfs(e[i].to);
        }
    //    for(int i=1;i<=n;i++)
    //        printf("i=%d v=%d bh=%d
    ",i,dp[i].v,dp[i].bh);
    //    for(int i=1;i<=n;i++)
    //        printf("dp[%d]=%d
    ",i,dp[i].v);
        while(reg<m)
        {
            int mx=-10005;
            int d,k;
            for(int i=1;i<=ed&&reg<m;i++)
            {
                if(use2[i])continue;
                int u=e[i].to;
                if(dp[u].v-e[i].w>mx)
                {
                    mx=dp[u].v-e[i].w;
    //                cout<<dp[u].v<<" "<<e[i].w<<endl;
                    d=u;k=i;
                }
            }
    //        printf("mx=%d d=%d k=%d
    ",mx,d,k);
            if(mx<=0)break;
            cost-=mx;
            use[dp[d].bh]=0;
            use2[k]=1;
            reg++;
            dp[d].v=-1;
            memset(vis,0,sizeof vis);
            vis[d]=1;
            dfs(d);
        }
        printf("Total miles driven: %d
    ",cost);
        return 0;
    }
    失败版

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<map>
    #include<cstring>
    #include<algorithm>
    #include<string>
    using namespace std;
    int n,m,ct,cnt,fa[250],cost,reg,key[250],mne[250],inf=0x3f3f3f3f;
    string s1,s2;
    map<string, int>mp;
    struct N{
        int hd,to,w;
    }edge[50000];
    struct NN{
        int w,u,v;
    }dp[50000];
    bool in[250][250];
    int sid[250][250];
    bool cmp(N x,N y){return x.w<y.w;}
    int find(int x)
    {
        if(x==fa[x])return x;
        return fa[x]=find(fa[x]);
    }
    void kruskal()
    {
        sort(edge+1,edge+ct+1,cmp);
    //    for(int i=1;i<=ct;i++)
    //        printf("w=%d u=%d v=%d
    ",edge[i].w,edge[i].hd,edge[i].to);
        for(int i=1;i<=cnt;i++)fa[i]=i;//
        for(int i=1;i<=ct;i++)
        {
            int u=edge[i].hd;
            int v=edge[i].to;
            if(u==1||v==1)continue;
            if(find(u)!=find(v))
            {
                cost+=edge[i].w;
                fa[find(u)]=find(v);
                in[u][v]=in[v][u]=1;
            }
        }
    }
    void dfs(int x,int f)
    {
        for(int u=2;u<=cnt;u++)
        {
            if(!in[x][u]||u==f)continue;
            if(dp[u].w==-1)
            {
                if(dp[x].w>sid[x][u])
                    dp[u]=dp[x];
                else
                {
                    dp[u].w=sid[x][u];
                    dp[u].u=x;dp[u].v=u;
                }
            }
            dfs(u,x);
        }
    }
    int main()
    {
        scanf("%d",&n);
        mp["Park"]=++cnt;
        memset(sid,0x3f,sizeof sid);
        for(int i=1;i<=n;i++)
        {
            int x;
            cin>>s1>>s2>>x;
            if(!mp[s1])mp[s1]=++cnt;
            if(!mp[s2])mp[s2]=++cnt;
            int m1=mp[s1],m2=mp[s2];//!
            sid[m1][m2]=sid[m2][m1]=min(sid[m1][m2],x);
            edge[++ct].w=x;
            edge[ct].hd=m1;edge[ct].to=m2;
        }
        scanf("%d",&m);
        kruskal();
    //    for(int i=1;i<=cnt;i++)
    //        for(int j=1;j<=cnt;j++)
    //            if(in[i][j])printf("in[%d][%d]=%d
    ",i,j,in[i][j]);
    //    cout<<cost<<endl;
        memset(mne,0x3f,sizeof mne);
        for(int i=2;i<=cnt;i++)
        {
            if(sid[i][1]==inf)continue;
            int cr=find(i);
            if(mne[cr]>sid[i][1])
            {
                mne[cr]=sid[i][1];
                key[cr]=i;
            }
        }
        for(int i=1;i<=cnt;i++)//
        {
            if(mne[i]==inf)continue;
    //        cost+=mne[i];
            cost+=sid[1][key[i]];//
            in[1][key[i]]=in[key[i]][1]=1;
            reg++;
        }
        for(int j=reg+1;j<=m;j++)
        {
            memset(dp,-1,sizeof dp);
            dp[1].w=-inf;
            for(int i=2;i<=cnt;i++)
            {
                if(in[i][1])dp[i].w=-inf;
    //            else dp[i].w=-1;
            }
            dfs(1,-1);
            int mn=inf;
            int d;
            for(int i=2;i<=cnt;i++)
            {
    //            if(sid[i][1]==inf)continue;
                if(sid[i][1]-dp[i].w<mn)
                {
                    mn=sid[i][1]-dp[i].w;
                    d=i;
                }
            }
            if(mn>=0)break;
            cost+=mn;
            in[dp[d].u][dp[d].v]=in[dp[d].v][dp[d].u]=0;
            in[1][d]=in[d][1]=1;
        }
        printf("Total miles driven: %d
    ",cost);
        return 0;
    }
  • 相关阅读:
    洛谷 P1048 采药
    一本通 1267:【例9.11】01背包问题
    一本通 1265:【例9.9】最长公共子序列
    一本通 1282:最大子矩阵
    一本通 1285:最大上升子序列和
    一本通 1284:摘花生
    一本通 1283:登山
    一本通 1264:【例9.8】合唱队形
    洛谷 P1126 机器人搬重物
    洛谷P1522 牛的旅行 Cow Tours
  • 原文地址:https://www.cnblogs.com/Zinn/p/8767787.html
Copyright © 2020-2023  润新知