JZOJ 3514. 最小比例

题目

Description

图中共有N个点的完全图,每条边都有权值,每个点也有权值。要求选出M个点和M-1条边,构成一棵树,使得:



即所有边的权值与所有点的权值之和的比率最小。 

给定N和M,以及N个点的权值,和所有的边权,要求M个点的最小比率生成树。
 

Input

第一行包含两个整数N和M(2<=N<=15,2<=M<=N),表示点数和生成树的点数。 

接下来一行N个整数,表示N个点的边权。 

最后N行,每行N列,表示完全图中的边权。所有点权和边权都在[1,100]之间。

Output

输出最小比率生成树的M个点。当答案出现多种时,要求输出的第一个点的编号尽量小,第一个相同,则第二个点的编号尽量小,依次类推,中间用空格分开。编号从1开始。
 

Sample Input

输入1:
3 2
30 20 10
0 6 2
6 0 3
2 3 0
输入2:
2 2
1 1
0 2
2 0

Sample Output

输出1:
1 3
输出2:
1 2
 

Data Constraint

对于30%数据,N<=5。

 

分析

 

  • n这么小显然暴力
  • 因为每次我们选的点是一定的
  • 所以我们要求最小边,最小生成树即可

 

代码

 1 #include<iostream>
 2 #include<vector>
 3 #include<cstdio>
 4 #include<cstring>
 5 using namespace std;
 6 int map[30][30];
 7 int t[30],b[30],flag[30],ans[30],dis[30],vis[30],fz1,fz2,fm1,fm2;
 8 double last=10000000000.0000;
 9 int n,m;
10 void check(int sum)
11 {
12         int cnt=0,anss=1e9;
13         int a=b[1];
14         memset(dis,0x3f,sizeof(dis));
15         memset(vis,0,sizeof(vis));
16         dis[a]=0;
17         vis[a]=1;
18         for (int j=2;j<=m;j++)
19            dis[b[j]]=min(dis[b[j]],map[a][b[j]]); 
20         int ss=0;
21         cnt=0;
22         while (++cnt<=m-1)
23         {
24             int wz=0,minn=1e9;
25             for (int j=1;j<=m;j++)
26             {
27                 int y=b[j]; 
28                 if (!vis[y]&&dis[y]<minn)
29                 {
30                     minn=dis[y];
31                     wz=y;
32                 }
33             }
34             vis[wz]=1;
35             for (int j=1;j<=m;j++)
36             {
37                 int y=b[j];
38                 if (!vis[y])
39                     dis[y]=min(dis[y],map[wz][y]);
40             }
41             ss+=minn;
42         }
43     anss=min(anss,ss);
44     double k=(double)anss/(double)sum;
45     if (k<last)
46     {
47         last=k;
48         for (int i=1;i<=m;i++)
49           ans[i]=b[i];
50     }
51 }
52 void dfs(int f,int sum)
53 {
54     if (f>m)
55     {
56         check(sum);
57         return;
58     }
59     for (int i=b[f-1]+1;i<=n;i++)
60     {
61         if (!flag[i])
62         {
63             flag[i]=1;
64             b[f]=i;
65             dfs(f+1,sum+t[i]);
66             flag[i]=0;
67         }
68     }
69 }
70 int main ()
71 {
72     freopen("ratio.in","r",stdin);
73     freopen("ratio.out","w",stdout);
74     cin>>n>>m;
75     for (int i=1;i<=n;i++)
76        cin>>t[i];
77     for (int i=1;i<=n;i++)
78       for (int j=1;j<=n;j++)
79         cin>>map[i][j];
80     dfs(1,0);
81     for (int i=1;i<=m;i++) cout<<ans[i]<<" ";
82 } 

 

posted @ 2019-08-21 20:37  Melted_czj  阅读(133)  评论(0编辑  收藏  举报
body { background-color:whitesmoke; } // 修改背景颜色为半透明 #home,#sideBarMain>div,#blog-sidecolumn>div>div,.catListView{ background-color:rgba(255,255,255,0); } // 修改其他边框的颜色