HDU-2489 DFS暴力+最小生成树

Minimal Ratio Tree

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


 

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个点,然后给出边的权值,输出任意选m个点之后组成的树的比例值(比例值=边的权值和 / 点的值和)最小的树的点 ,输入0 0结束

思路:就是先用dfs或者状压dp暴力选出m个点,然后用最小生成树来计算边的权值和,要使比例值最小,边的权值和就要相对于的小。。。比如找到了m个点,我们要计算边的权值和最小才能让组成的树的比例值变小。一开始我不知道为什么要用最小生成树,后面才知道。。。

坑点:看其他dalao的博客好像是dfs  m个点的时候会超时,到时候我们注意下就行了

AC代码:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=20;
const double INF=999999999;
double map[maxn][maxn],val[maxn],dis[maxn];     //val用来记录点的值
int sum[maxn],ans[maxn],n,m;                   //sum是找到的m个点,ans是要找的最小比例值的m个点
bool vis[maxn],flag;
double Min;                    //Min用来判断比例值的
double prim()
{
    bool vis_p[maxn];
    memset(vis_p,false,sizeof(vis_p));
    for (int i=1;i<=m;i++)
        dis[i]=INF;
    dis[1]=0;
    for (int i=1;i<=m;i++)
        {
            double MIN=INF;int flag;
            for (int j=1;j<=m;j++)
                if (vis_p[j]==true) continue;
                else if (MIN>dis[j])
                        {
                            MIN=dis[j];
                            flag=j;
                        }
            if (MIN==INF)
                break;
            vis_p[flag]=true;
    //        cout<<MIN<<" -- "<<flag<<endl;
    //        cout<<MIN<<" -- "<<flag<<" ";
            for (int j=1;j<=m;j++)
                if (vis_p[j]==true) continue;
                else dis[j]=min(dis[j],map[sum[flag]][sum[j]]);
        }
//    cout<<endl;
    double s=0;
    for (int i=1;i<=m;i++)
        s=s+dis[i];
    return s;
}
void dfs(int num,int step)     //一开始 num==1,后面for 循环的时候我们的i从Num开始,因为如果不从num开始我们会有这种情况
{                               //   sum里面是1 2 3   之后又会出现  1 3 2,这两种情况是一样的,避免重复
    if (step==m+1)         //如果找到m个点就计算点的值和  和   边的权值和
        {
            sort(sum+1,sum+step);
            double sum1=prim();
            double sum2=0;
            for (int i=1;i<step;i++)
                sum2=sum2+val[sum[i]];
    //        cout<<Min<<"???"<<(sum1/sum2)<<endl;
            if (Min>(sum1/sum2))
                {
                    Min=sum1/sum2;
                    for (int i=1;i<step;i++)     //记录最小比例值的树的点
                        ans[i]=sum[i];
    //                cout<<"OK"<<endl;
                }
    //        for (int i=1;i<step;i++)
    //            if (i==step-1) cout<<sum[i]<<endl;
    //            else cout<<sum[i]<<"-"; 
    //        cout<<sum1<<"---"<<sum2<<endl;
            return ;
        }
    for (int i=num;i<=n;i++)
        if (vis[i]==true) continue;
        else 
            {
    //            cout<<step<<"------"<<i<<endl;
                vis[i]=true;
                sum[step]=i;
                dfs(i,step+1);
                vis[i]=false;
            }
}
int main()
{
    int i,j;
    while (cin>>n>>m&&n&&m)
        {
            memset(val,0,sizeof(val));
            for (i=1;i<=n;i++)
                scanf("%lf",&val[i]);
            for (i=1;i<=n;i++)
                for (j=1;j<=n;j++)
                    scanf("%lf",&map[i][j]);
            memset(vis,false,sizeof(vis));
            memset(ans,0,sizeof(ans));Min=INF;
            dfs(1,1);
            for (i=1;i<=m;i++)
                if (i==m) cout<<ans[i]<<endl;
                else cout<<ans[i]<<" ";
        }
    return 0;
}
发布了46 篇原创文章 · 获赞 2 · 访问量 3216

猜你喜欢

转载自blog.csdn.net/z1164754004z/article/details/86563156