HDU Minimal Ratio Tree

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.


  题意:输入n个点,要求选m个点满足连接m个点的m-1条边权值和sum与点的权值和ans最小,即sum/ans最小,并输出所选的m个点,如果有多种情况就选第一个点最小的,如果第一个点也相同就选第二个点最小的........

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

题解

数据太小了,可以用dfs枚举组合情况再在此基础上做最小生成树,看百度上都是prim的,我就打了一个Kruskal的。
可是我还太年轻,多组数据时边表忘清零了,wa了将近10次敲打  大哭
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,d[17],zz=0,head[17],fa[17],ansd[17],dz;
double ans;
bool pd[17];
struct bian
{int fr,to,nx,v;} e[250];
void insert(int x,int y,int z)
{zz++; e[zz].fr=x; e[zz].to=y; e[zz].v=z; e[zz].nx=head[x]; head[x]=zz;}
bool kp(const bian &x,const bian &y)
{
	if(x.v<y.v) return true;
	else return false;
}
int find(int x)
{
	if(fa[x]!=x) fa[x]=find(fa[x]);
	return fa[x];
}
double klskl()
{
	int sumd=0,suml=0;
	double sd,sl;
	for(int i=1;i<=n;i++)
	   {if(pd[i])
	      {fa[i]=i; sumd+=d[i];}
	   }
	for(int i=1;i<=zz;i++)
	   {if(pd[e[i].fr]&&pd[e[i].to])
	       {int r1=find(e[i].fr),r2=find(e[i].to);
		    if(r1!=r2)
		       {suml+=e[i].v; fa[r2]=r1;}
		   }
	   }
	sd=sumd*1.0; sl=suml*1.0;
	return sl/sd;
}
void dfs(int w,int s)
{
	if(s==m)
	   {
		double ratio=klskl();
        if(ratio<ans)
           {dz=0; ans=ratio; 
			for(int i=1;i<=n;i++)
		       {if(pd[i]) {dz++; ansd[dz]=i;}} 
		   }
		return ;
       }
	if(w>n) return;
    pd[w]=true;
    dfs(w+1,s+1);
    pd[w]=false;
    if(n-w+s>=m) dfs(w+1,s);//为了做如2,3,5,6这样的情况 
}
int main()
{
    while(scanf("%d%d",&n,&m)&&n&&m)
       {zz=0;
		for(int i=1;i<=n;i++) scanf("%d",&d[i]);
	    for(int i=1;i<=n;i++)
	    for(int j=1;j<=n;j++)
	       {int x;
			scanf("%d",&x);
			if(i!=j) insert(i,j,x);
		   }
		memset(pd,false,sizeof(pd));
		//memset(ansd,0,sizeof(ansd));
		ans=99999999.1;
		sort(e+1,e+zz+1,kp);
		dfs(1,0);
		int sc=0;
		for(int i=1;i<=dz;i++)
		   {if(sc!=0) printf(" ");
		    printf("%d",ansd[i]); sc=1;
		   }
		printf("\n");
	   }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值