• POJ-1639 Picnic Planning 度数限制最小生成树


     解法参考的论文:https://wenku.baidu.com/view/8abefb175f0e7cd1842536aa.html

    觉得网上的代码好像都是用邻接矩阵来实现的,觉得可能数据量大了会比较慢。于是自己写了一遍。

    实现细节可以看代码:

    #include<iostream>
    #include<cstdio> 
    #include<cstring>
    #include<algorithm>
    #include<map>
    #include<vector>
    using namespace std;
    const int N=10000+10;
    const int INF=0x3f3f3f3f;
    int n,m,k,ans,fa[N];
    struct edge{
        int x,y,z;
        bool used;
        edge() {}
        edge(int x,int y,int z) : x(x),y(y),z(z) { used=0; }
        bool operator < (const edge &rhs) const {
            return z<rhs.z;
        }
    }e[N];
    map<string,int> mp;
    vector<int> G[N];
    
    int getfa(int x) { return x==fa[x] ? x : fa[x]=getfa(fa[x]); } 
    
    void kruskal() {
        sort(e+1,e+m+1);
        for (int i=1;i<=n;i++) fa[i]=i;
        for (int i=1;i<=m;i++) {
            int fx=getfa(e[i].x),fy=getfa(e[i].y);
            if (e[i].x==1 || e[i].y==1 || fx==fy) continue;
            fa[fy]=fa[fx];
            e[i].used=1;
            ans+=e[i].z;
        }
    }
    
    int Max[N];
    void dfs(int x,int f) {
        for (int i=0;i<G[x].size();i++) {
            int y; if (e[G[x][i]].x==x) y=e[G[x][i]].y; else y=e[G[x][i]].x;
            if (!e[G[x][i]].used || y==f) continue;
            if (x!=1) //这个很重要:去掉的边必须和V0不相连(否则会使得根节点度数减少) 
            if (Max[x]==0 || e[G[x][i]].z>e[Max[x]].z) Max[y]=G[x][i];
                else Max[y]=Max[x]; 
            dfs(y,x);
        }
    }
    
    int cnt=0,Min[N];
    void solve() {
        memset(Min,0,sizeof(Min));
        for (int i=0;i<G[1].size();i++) {  //把各个MST森林最小边连到根节点 变成一棵树 
            int ty;
            if (e[G[1][i]].x==1) ty=getfa(e[G[1][i]].y);
                else ty=getfa(e[G[1][i]].x);
            if (Min[ty]==0 || e[G[1][i]].z<e[Min[ty]].z) Min[ty]=G[1][i];     
        }
        for (int i=1;i<=n;i++)
            if (Min[i]) { cnt++; ans+=e[Min[i]].z; e[Min[i]].used=1; }
            
        for (int i=cnt+1;i<=k;i++) {  //拓展根节点度数 
            memset(Max,0,sizeof(Max));
            dfs(1,0);  //dfs找每个点到根节点的路径上的最长边 
            int minn=INF,New,Old;
            for (int j=0;j<G[1].size();j++)
                if (!e[G[1][j]].used) {
                    int y; if (e[G[1][j]].x==1) y=e[G[1][j]].y; else y=e[G[1][j]].x;  
                    if (Max[y]==0) continue;
                    int tmp=e[G[1][j]].z-e[Max[y]].z;
                    if (tmp<minn) {  //记录本次结点拓展最大的收益 
                        minn=tmp;
                        New=G[1][j]; Old=Max[y];
                    }
                }
            if (minn>=0) break;
            ans+=minn;
            e[New].used=1; e[Old].used=0;  //替换最长边 
        }
    } 
    
    int main()
    {
        cin>>m;
        string s1,s2; int x,y,z;
        n=1; mp["Park"]=1;
        for (int i=1;i<=m;i++) {
            cin>>s1>>s2>>z;
            if (!mp.count(s1)) mp[s1]=++n;
            if (!mp.count(s2)) mp[s2]=++n;
            x=mp[s1]; y=mp[s2];
            e[i]=edge(x,y,z);
        }
        cin>>k;
        
        kruskal();  //先忽略根节点做一次MST 得到MST森林 
        for (int i=1;i<=m;i++) { G[e[i].x].push_back(i); G[e[i].y].push_back(i); }
        solve();  //拓展根节点度数得到更小的MST 
        
        printf("Total miles driven: %d
    ",ans);
        return 0;
    }
  • 相关阅读:
    Oracle:SQL语句--撤销用户权限
    Oracle:SQL语句--给用户赋权限
    RSTP端口状态迁移过程详解
    LSB算法分析与实现
    工厂方法模式
    Ceasar
    区域性名称和标识符
    Packet Tracer网络模拟实验实记
    H3C-OSPF
    H3C-RIP
  • 原文地址:https://www.cnblogs.com/clno1/p/10697295.html
Copyright © 2020-2023  润新知