HDU 2489 Minimal Ratio Tree By Assassin

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

思路:

思路其实很简单,我们看到了数据不超过15,那么直接dfs搜索枚举各种node的组合情况,而对于每一种情况来说nodesum时固定的,就找到最小的edgesum就行了,这个要用prime算法生成最小生成树。

之前不会prime,大概想了一下,就是每次从已经选乐的节点中找到最短的向外延伸的边,最后把端点的另一头加到已经访问的端点里

(我自己写的代码很难看而且不太适用,最好学习一下prime的模板)

#include<stdio.h>
#include<iostream>
#include<string.h>
#define input freopen("input.txt","r",stdin)
using namespace  std;
int m,n;
int value[30],v[30];
double ratio;
int key[30][30],mapv[30][30];
int writev[30];
void handle()
{
    int i,j,k,use[30];
    int pos=0,minn;
    int edgesum=0,nodesum=0;
    memset(mapv,0,sizeof(mapv));
    memset(use,0,sizeof(use));
//  for(i=1;i<=n;i++)
//  {
//      cout<<v[i]<<" ";
//  }cout<<endl;
    for(i=1;i<=n;i++)
    {
        if(v[i])
        {
            use[i]=1;
            break;
        }
    }
    for(k=1;k<m;k++)
    {
        minn=10000;
        for(i=1;i<=n;i++)
        {
            if(use[i])
            {
                for(j=1;j<=n;j++)
                {
                    if(v[j]&&!use[j]&&key[i][j]<minn)
                    {
                        pos=j;
                        minn=key[i][j];
                    }
                }
            }
        }
        use[pos]=1;
        edgesum+=minn;
    }
    for(i=1;i<=n;i++)
    {
        if(v[i])
        {
            nodesum+=value[i];
        }
    }
    if(edgesum*1.0/nodesum<ratio)
    {
        ratio=edgesum*1.0/nodesum;
        for(i=1;i<=n;i++)
        {
            writev[i]=v[i];
        }
    }

}
void dfs(int pos,int time)
{
    int i;
    if(time<0||time>m+1)return ;
    if(time==m) handle();
    for(i=pos+1;i<=n;i++)
    {
        v[i]=1;
        dfs(i,time+1);
        v[i]=0;
    }
}
int main()
{
    input;
    int i,j;
    while(cin>>n>>m)
    {
        if(n==0&&m==0)break;
        memset(writev,0,sizeof(writev));
        for(i=1;i<=n;i++) 
            cin>>value[i];
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
                cin>>key[i][j];
        ratio=10000;
        for(i=1;i<=n;i++)
        {
            v[i]=1;
            dfs(i,1);
            v[i]=0;
        }
        int flag=0;
        for(i=1;i<=n;i++)
        {
            if(writev[i])
            {
                if(flag)cout<<" ";
                flag=1;
                cout<<i;
            }
        }cout<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值