zoukankan      html  css  js  c++  java
  • HDU 2489 Minimal Ratio Tree(dfs枚举+最小生成树)

    想到枚举m个点,然后求最小生成树,ratio即为最小生成树的边权/总的点权。
    但是怎么枚举这m个点,实在不会。
    网上查了一下大牛们的解法,用dfs枚举,没想到dfs还有这么个作用。

    参考链接:http://blog.csdn.net/xingyeyongheng/article/details/9373271

    #include <stdio.h>
    #include <string.h>
    #include <set>
    #include <vector>
    #include <queue>
    
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    int n,m,tot; //tot为选取的m个点的总权值
    int choseNode[16];  //存储选取的m个点
    int tmp[16];  //存储最小ratio的m个点
    int nodew[16],w[16][16];  //nodew[i]存储点i的权值,w[i][j]存储边的权值
    int dis[16],vis[16];
    double minratio=0x3f3f3f3f;
    
    int prim(){
        int ans=0;
        memset(dis,INF,sizeof(dis));
        memset(vis,0,sizeof(vis));
        int t,idx;
        dis[choseNode[0]]=0;
        for(int i=1;i<=m;i++){
            t=INF;
            for(int i=0;i<m;i++){
                if(!vis[choseNode[i]] && dis[choseNode[i]]<t){
                    t=dis[choseNode[i]];
                    idx=choseNode[i];
                }
            }
            vis[idx]=1;
            ans+=t;
            for(int i=0;i<m;i++){
                int u=choseNode[i];
                if(!vis[u] && w[idx][u]<dis[u]){
                    dis[u]=w[idx][u];
                }
            }
        }
        return ans;
    }
    /*
    dfs枚举m个点,num代表目前选取了多少个点,k代表第num个点为k。
    表示前num个点选自1~k,剩余的点从k+1~n中选。
    */
    void dfs(int k,int num){
        if(num==m){
            tot=0;
            for(int i=0;i<m;i++){
                tot+=nodew[choseNode[i]];
            }
            int sum=prim();
            double tmpratio=sum*1.0/tot;
            if(tmpratio<minratio){
                minratio=tmpratio;
                for(int i=0;i<m;i++){
                    tmp[i]=choseNode[i];
                }
            }
            return;   //忘记写return了。。。
        }
        //若剩余的点的个数(n-k)加上目前选取的个数num小于m的话,说明即使接下来n-k个点都选取,也选不足m个点,直接return
        if(n-k+num<m)
            return;
        for(int i=k+1;i<=n;i++){
            //选的点用数组存起来
            choseNode[num]=i;
            dfs(i,num+1);
        }
    }
    int main()
    {
        int a;
        while(scanf("%d%d",&n,&m)!=EOF){
            if(n==0 && m==0)
                break;
            memset(w,0,sizeof(w));
            minratio=INF*0.1;
            for(int i=1;i<=n;i++){
                scanf("%d",&nodew[i]);
            }
            for(int i=1;i<=n;i++){
                for(int j=1;j<=i;j++)
                    scanf("%d",&a);
                for(int j=i+1;j<=n;j++){
                    scanf("%d",&a);
                    w[i][j]=w[j][i]=a;
                }
            }
            for(int i=1;i<=n;i++){
                choseNode[0]=i;
                dfs(i,1);
            }
            for(int i=0;i<m-1;i++){
                printf("%d ",tmp[i]);
            }
            printf("%d",tmp[m-1]);
            printf("
    ");
        }
        return 0;
    }

    最后再附上网上看到的另一种dfs枚举的写法:

    //调用时:dfs(1,0,0);
    
    //dep表示点的编号,cnt表示选取的点的个数,sum_pw表示目前选取了cnt个点后总的点权值
    void dfs(int dep, int cnt, int sum_pw) {
        if(cnt == m) {
            ...;
            return ;
        }
        if(dep == n + 1) return ;
        use[dep] = true;  //选取点dep,这里use[i]=true表示选取点i,在用prim求最小生成树的时候有用
        dfs(dep + 1, cnt + 1, sum_pw + weight[dep]);
        use[dep] = false; //不选取点dep
        dfs(dep + 1, cnt, sum_pw);
    }
  • 相关阅读:
    Silverlight4实现三维企业网站
    (学)Lazarus 字符串压缩、解压缩
    (原)Oracel 函数返回 Decimal 丢失小数位问题
    (原)如何提高软件运行速度
    (转) ORA01033: ORACLE 正在初始化或关闭
    (学)正在写一个陌生行业的方案,努力ing
    (学)Telerik GridFoot 如何加合计
    (思)爱的路上千万里
    (学)Telerik RadGridView 中Column 数据字段绑定
    写在2011年伊始
  • 原文地址:https://www.cnblogs.com/chenxiwenruo/p/3294668.html
Copyright © 2011-2022 走看看