HDU2489——不全包含顶点的最小生成树

题目的大概意思是,给定n个顶点和这些顶点的邻接矩阵,求Ratio值最小(边权和/点权和)的含m个顶点的最小生成树并输出。(输出顶点时从小到大输出)

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. 
InputInput 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. 

OutputFor 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


代码:

//
//  main.cpp
//  HDU2489
//
//  Created by jinyu on 2018/7/15.
//  Copyright © 2018年 jinyu. All rights reserved.
//

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;

int N,M;

struct dingD{
    int weight;
    int index;
};
dingD d[20];

int arc[20][20];
int visited1[20] = {0} ;
int dist[20];

vector<int> selected;
double MINRADTIO = INF;


void Prim(vector<int> s,int sum){
    double res = 0;
    for(int i = 1;i<=N;i++)
    {
        visited1[i] = 0;
        dist[i] = arc[s[0]][i];
        
    }
    visited1[s[0]] = 1;
    for(int i = 1;i<M;i++){
        int pos = s[0];
        int min = INF;
        for(int j = 0;j<M;j++){
            if(!visited1[s[j]] && dist[s[j]]<min){
                min = dist[s[j]];
                pos = s[j];
            }
        }
        visited1[pos] = 1;
        res += min;
        for(int k =0;k<M;k++){
            if( dist[s[k]] > arc[pos][s[k]]){
                dist[s[k]] = arc[pos][s[k]];
            }
        }
    }
    res = (double)res/sum;
    if(res<MINRADTIO)
    {
        MINRADTIO = res;
        selected = s;
    }
}

void dfs(vector<int> s,int num,int sum,int index){
    if(num==M){
        Prim(s,sum);
        return ;
    }
    for(int i = index+1;i<=N;i++){
            s.push_back(i);
            dfs(s,num+1,sum+d[i].weight,i);
            s.pop_back();
    }
    
}


int main(){
    
    cin>>N>>M;
    while(N!=0 && M!=0){
        for(int i = 1;i<=N;i++){
            visited1[i] = 0;
            for(int j = 1;j<=N;j++){
                arc[i][j] = INF;
            }
        }
        int nn = N;
        while(nn--){
            int w;
            cin>>w;
            d[N-nn].weight = w;
        }
        for(int i = 1;i<=N;i++){
            for(int j = 1;j<=N;j++){
                cin>>arc[i][j];
            }
        }
        vector<int> s;
        dfs(s,0,0,0);
        sort(selected.begin(),selected.end());
        cout<<selected[0];
        for(int i = 1;i<selected.size();i++){
            cout<<" "<<selected[i];
        }
        cout<<endl;
        selected.clear();
        MINRADTIO = INF;
        cin>>N>>M;
    }
    
    return 0;
}


刚看到题时就想直接枚举所有顶点的m阶最小生成树,但其实这样是得不到所有m阶最小生成树的,会有重复。于是想到采用dfs的方法,将它分成多个包含m个顶点的子图,并把子图顶点存到vector s中,再对每个s进行Prim。

这里第一次提交时出现了TLE,原因是在dfs中没有多想就直接用个数组来判断当前结点是否被访问,每次都去循环n次,结果导致超时。这样其实中间有会出现多次重复,需要优化一下。具体就是设置一个参数index,每次递进搜索只搜索下标比index大的结点,这样不会得到重复的集合,时间也大大优化。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值