您的位置:首页 > 其它

hdu2489 Minimal Ratio Tree dfs+最小生成树

2013-08-04 14:22 363 查看
题目大意是Ratio的计算方法是边的权值除以节点的权值。由此计算带有点权值和边权值的图n,计算出一个子图m,子图m的Ratio在所有m个顶点的树中是最小的。

那么对于同一m个节点的子图中,其节点的权值是相同的,只需我们找出m个节点的最小的边权值和,即最小生成树Prim。

首先将n个节点进行dfs搜索,达到m个节点的时候进行最小生成树的计算。在计算Ratio的时候要进行精度的判断,不然就是wrong answer。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cctype>
using namespace std;
#define INF 0xffff
int a[16][16];//边权值
int node[16];//点权值
int vit[16],vit2[16];
int arr[16];//结果
int dist[20];
int n,m,flag;
double ans;
int Prim()
{
int ret=0;
memset(dist,0,sizeof(dist));
int sta;
//找到搜索结果的第一个点并作为树的第一个顶点。
for(int i=1;i<=n;i++)
{
if(vit[i])
{
sta=i;
break;
}
}
vit2[sta]=1;
dist[sta]=0;
for(int i=1;i<=n;i++)
{
if(vit[i])
dist[i]=a[sta][i];
}
for(int i=1;i<m;i++)
{
int MIN=INF;
int tmp=-1;
for(int j=1;j<=n;j++)
{
if(vit[j]&&!vit2[j]&&MIN>dist[j])
{
MIN=dist[j];
tmp=j;
}
}
vit2[tmp]=1;
ret+=MIN;
for(int j=1;j<=n;j++)
{
if(!vit2[j]&&vit[j]&&dist[j]>a[tmp][j])
{
dist[j]=a[tmp][j];
}
}
}
return ret;
}
void dfs(int dep)
{
if(flag == m)
{
memset(vit2,0,sizeof(vit2));
int ret = Prim();
int sum=0;
for(int i=1;i<=n;i++)
if(vit[i])
sum+=node[i];
double ans_tmp=(double)ret/(double)sum;
if(ans_tmp-ans<-(1e-9))//这里判断精度很重要!
{
ans=ans_tmp;
for(int i=1;i<=n;i++)
arr[i]=vit[i];
}
return ;
}
for(int i=dep;i<=n;i++)
{
if(!vit[i])
{
flag++;
vit[i]=1;
dfs(i);
flag--;
vit[i]=0;
}
}
return ;
}
int main()
{
while(cin>>n>>m)
{
if(n == 0&&m == 0)
break;
memset(a,INF,sizeof(a));
for(int i=1;i<=n;i++)
cin>>node[i];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j];
ans=(double)INF;
memset(vit,0,sizeof(vit));
flag=0;
dfs(1);
bool ans_flag=true;
for(int i=1;i<=n;i++)
{
if(arr[i])
{
if(ans_flag)
{
cout<<i;
ans_flag = false;
}
else
cout<<" "<<i;
}
}
cout<<endl;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: