hdu 2489 Minimal Ratio Tree


题目链接:



http://acm.hdu.edu.cn/showproblem.php?pid=2489


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<=15),每个边都有权值,每个点也都有权值,求一个有m个节点的树,使得该树的边权值和和点权值和是所有m个节点的树中最小的。如果有多种解,则输出将节点编号从小到大排序后,字典序最小的那个解


思路:n很小,故可以直接枚举可能C(n,m)中m个点的情况,对m个点求其最小生成树,记录比较比值最小的生成树的节点


程序:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int INF=10000000;
int n,m,nw[20],e[20][20],a[20],arr[20];
double ans;
bool used[20];

int prim(){
    int i,j,d[20],flag[20],sum=0;
    memset(flag,0,sizeof flag);
    fill(d,d+20,INF);
    d[a[1]]=0;
    while (1){
        int v=-1;
        for (i=1;i<=m;i++){
            if (!flag[a[i]] && (v==-1 || d[a[v]]>d[a[i]])) v=i;
        }
        if (v==-1) return sum;
        flag[a[v]]=1;
        sum+=d[a[v]];
        for (i=1;i<=m;i++)
            if (!flag[a[i]]) d[a[i]]=min(d[a[i]],e[a[v]][a[i]]);
    }
}

void dfs(int k,int l){
    int i,j;
    if(n-l<m-k) return;
    if (k>m){
        int nw_sum=0;
        for (i=1;i<=m;i++){
            nw_sum+=nw[a[i]];
        }
        int ew_sum=prim();
        if (abs(ans-ew_sum*1.0/nw_sum)>=0.00000008&&ans>ew_sum*1.0/nw_sum){
            ans=ew_sum*1.0/nw_sum;
            for (i=1;i<=m;i++)
                arr[i]=a[i];
        }
        return;
    }
    for (i=l;i<=n;i++){
        if (!used[i]){
            used[i]=true;
            a[k]=i;
            dfs(k+1,i);
            used[i]=false;
        }
    }
}
int main(){
    int i,j;
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    while (scanf("%d%d",&n,&m)==2 &&(n+m)>0){
        ans=INF;
        for (i=1;i<=n;i++)
            scanf("%d",&nw[i]);
        for (i=1;i<=n;i++)
            for (j=1;j<=n;j++)
                scanf("%d",&e[i][j]);
        memset(used,0,sizeof used);
        dfs(1,1);
        for (i=1;i<m;i++)
            printf("%d ",arr[i]);
        printf("%d\n",arr[m]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值