zoukankan      html  css  js  c++  java
  • HDU 2489 Minimal Ratio Tree(prim+DFS)

    Minimal Ratio Tree

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 3345    Accepted Submission(s): 1019


    Problem Description
    For a tree, which nodes and edges are all weighted, the ratio of it is calculated according to the following equation.




    Given a complete graph of n nodes with all nodes and edges weighted, your task is to find a tree, which is a sub-graph of the original graph, with m nodes and whose ratio is the smallest among all the trees of m nodes in the graph.
     

    Input
    Input contains multiple test cases. The first line of each test case contains two integers n (2<=n<=15) and m (2<=m<=n), which stands for the number of nodes in the graph and the number of nodes in the minimal ratio tree. Two zeros end the input. The next line contains n numbers which stand for the weight of each node. The following n lines contain a diagonally symmetrical n×n connectivity matrix with each element shows the weight of the edge connecting one node with another. Of course, the diagonal will be all 0, since there is no edge connecting a node with itself.



    All the weights of both nodes and edges (except for the ones on the diagonal of the matrix) are integers and in the range of [1, 100].

    The figure below illustrates the first test case in sample input. Node 1 and Node 3 form the minimal ratio tree. 

     

    Output
    For each test case output one line contains a sequence of the m nodes which constructs the minimal ratio tree. Nodes should be arranged in ascending order. If there are several such sequences, pick the one which has the smallest node number; if there's a tie, look at the second smallest node number, etc. Please note that the nodes are numbered from 1 .
     

    Sample Input
    3 2 30 20 10 0 6 2 6 0 3 2 3 0 2 2 1 1 0 2 2 0 0 0
     

    Sample Output
    1 3 1 2
     

    题意描写叙述:

    给出n个点的权值和这n个点之间的边的权值。从这n个点之中选出m个点使得这m个点的权值最大,这m个点的生成树中边的权值最小。即Ratio最小。依照升序输出这m个点。


    解题思路:

    首先n的范围是[2,15],所以能够用dfs搜索使得Ratio最小的点。那么思路基本清晰:首先dfs,搜索全部的点选与不选所得到的最大的Ratio。假设当前状态下得到的Ratio比之前得到的Ratio要小,那么把当前状态的vis数组更新的答案ans数组中。

    最后从1到n扫描ans数组就可以保证答案是升序。




    參考代码:

    #include<stack>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #pragma commment(linker,"/STACK: 102400000 102400000")
    using namespace std;
    const double eps=1e-6;
    const int INF=0x3f3f3f3f;
    const int MAXN=20;
    
    int n,m,mincost[MAXN],node[MAXN],edge[MAXN][MAXN];
    bool vis[MAXN],used[MAXN],ans[MAXN];
    double temp;
    
    double prim()
    {
        memset(mincost,0,sizeof(mincost));
        memset(used,false,sizeof(used));
        int s;
        for(int i=1; i<=n; i++)
            if(vis[i])
            {
                s=i;
                break;
            }
        for(int i=1; i<=n; i++)
        {
            mincost[i]=edge[s][i];
            used[i]=false;
        }
        used[s]=true;
        int res=0;
        int nodevalue=node[s];
        for(int j=1; j<n; j++)
        {
            int v=-1;
            for(int i=1; i<=n; i++)
                if(vis[i]&&!used[i]&&(v==-1||mincost[v]>mincost[i]))//vis[i]表示第i个点有没有被选中
                    v=i;
            res+=mincost[v];
            nodevalue+=node[v];
            used[v]=true;
            for(int i=1; i<=n; i++)
                if(vis[i]&&!used[i]&&mincost[i]>edge[v][i])
                    mincost[i]=edge[v][i];
        }
        return (res+0.0)/nodevalue;
    }
    
    void dfs(int pos,int num)
    {
        if(num>m)
            return ;
        if(pos==n+1)
        {
            if(num!=m)
                return ;
            double tans=prim();
            if(tans<temp)
            {
                temp=tans;
                memcpy(ans,vis,sizeof(ans));
            }
            return ;
        }
        vis[pos]=true;//选择当前点
        dfs(pos+1,num+1);
        vis[pos]=false;//不选择当前点,消除标记
        dfs(pos+1,num);
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
        while(scanf("%d%d",&n,&m))
        {
            if(n==0&&m==0)
                break;
            for(int i=1; i<=n; i++)
                scanf("%d",&node[i]);
            for(int i=1; i<=n; i++)
                for(int j=1; j<=n; j++)
                    scanf("%d",&edge[i][j]);
            temp=INF;
            dfs(1,0);
            bool flag=false;
            for(int i=1; i<=n; i++)
            {
                if(ans[i])
                {
                    if(flag)
                        printf(" ");
                    else
                        flag=true;
                    printf("%d",i);
                }
            }
            printf("
    ");
        }
        return 0;
    }


  • 相关阅读:
    BZOJ 1029 & 丝帛贪心
    BZOJ 1831 & 就是一个DP....
    HDU2138 & 米勒拉宾模板
    BZOJ 2733 & splay的合并
    hdu Matrix Multiplication 写一个类似哈希函数的东西一切就解决了。
    hdu Cow Sorting 数学题(值得思考)
    Find them, Catch them 并查集
    Buy Tickets 简单的线段树&&反向更新
    Who Gets the Most Candies? 线段树的建立更新和反素数
    Apple Tree 有时间戳的树状数组
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/7084603.html
Copyright © 2011-2022 走看看