标签:
3 2 30 20 10 0 6 2 6 0 3 2 3 0 2 2 1 1 0 2 2 0 0 0
1 3 1 2
题意:在一个n个点的图中取出m个点的生成树 每个点和边都有相应的权值 当前m个点的树 根据题中所给计算公式求出当前ratio最小的那个生成树 并按照点的顺序输出当前生成树中的点
题解:因为数据量不大的缘故 可以DFS遍历所有的点 用Prim算法求出最小生成树边的和 之后带入公式中 比较大小 最后找到ratio最小的情况
因为最小值的精度问题调了一晚上 不过还好一次AC
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 15+11;
const int inf = 0x7ffffff;
int n, m;
int edge[maxn][maxn], node[maxn], dist[maxn], temp[maxn], tree[maxn]; //edge-边 node-点 dist-Prim算法存放路径 temp-存放最小生成树用到的点 tree-存放最终答案的点
bool mark[maxn]; //标记
double minratio; //最小值
void dfs(int k, int num); //深搜
int prim(int u); //Prim
int main(){
while(scanf("%d%d", &n, &m)!=EOF && (n&&m)){ //输入nm
minratio = inf * 1.0; //最小值赋初值
for(int i = 1; i <= n; ++i){
scanf("%d", &node[i]); //输入点
}
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
scanf("%d", &edge[i][j]); //输入边
}
}
for(int i = 1; i <= n; ++i){ //取出起始点并进入DFS
temp[1] = i;
dfs(i, 1);
}
for(int i = 1; i < m; ++i){ //格式化输出
printf("%d ", tree[i]);
}
printf("%d\n", tree[m]);
}
return 0;
}
void dfs(int k, int num){
if(num == m){ //m个点 则 进入判断
int sum = 0; //存放点的权值和
for(int i = 1; i <= m; ++i){
sum += node[temp[i]];
}
double Ratio = prim(k) * 1.0 / sum; //Prim取出最小边的和 根据题目中所给的求出ratio
if(Ratio - minratio<-(1e-9)){ //因为浮点数 判断大小注意精度
minratio = Ratio;
for(int i = 1; i <= m; ++i){ //tree收入当前最小值的点
tree[i] = temp[i];
}
}
return ;
}
for(int i = k+1; i <= n; ++i){ //如果点的数目不足m 则 继续DFS
temp[num+1] = i;
dfs(i, num+1);
}
}
int prim(int u){
for(int i = 1; i <= n; ++i){
dist[temp[i]] = edge[u][temp[i]]; //dist赋值
}
memset(mark, false, sizeof(mark)); //标记赋初值
int sum = 0;
mark[u] = true; //已经放入最小生成树的点
dist[u] = 0;
for(int i = 1; i < m; ++i){
int point = u;
for(int j = 1; j <= m; ++j){ //找到与当前点之间边的权值最小的点
if(point == u && !mark[temp[j]]){
point = temp[j];
}
if(!mark[temp[j]] && dist[point] > dist[temp[j]]){
point = temp[j];
}
}
mark[point] = true; //将这个点收入最小生成树的集合
sum += dist[point]; //边的和
for(int j = 1; j <= m; ++j){ //更新当前最小生成树集合中的点与不在集合中的点之间边权值最小的边
if(!mark[temp[j]] && dist[temp[j]] > edge[point][temp[j]]){
dist[temp[j]] = edge[point][temp[j]];
}
}
}
return sum; //返回最小生成树边的权值和
}
标签:
原文地址:http://blog.csdn.net/u012431590/article/details/46274945