hdu 2489 Minimal Ratio Tree
https://vjudge.net/problem/HDU-2489
题意:求一个完全图的最优比率生成树,点的个数由题给出。最优比率生成树是边的权值之和与点的权值之和的比值最小的生成树。
思路:一开始用dfs枚举搜索每一种情况,t了,枚举的情况太多。之后看了题解,用的是状态压缩的方法枚举点的选择,这样的情况要少得多。至于其他的细节倒是很好想,由于比值最小,所以我们要求的是一棵最小生成树,再比上点的权值之和,最后选择出最小的就行了。
1 #include <stdio.h> 2 #include <string.h> 3 #include <map> 4 #include <algorithm> 5 using namespace std; 6 7 int n,m; 8 9 int par[20]; 10 int a[20][20]; 11 int b[20]; 12 13 struct node 14 { 15 int x,y,d; 16 } g[1000]; 17 18 void init(int k) 19 { 20 for (int i = 0;i <= k;i++) 21 par[i] = i; 22 } 23 24 int fin(int x) 25 { 26 if (x == par[x]) return x; 27 else return par[x] = fin(par[x]); 28 } 29 30 void unit(int x,int y) 31 { 32 x = fin(x); 33 y = fin(y); 34 35 if (x != y) par[x] = y; 36 } 37 38 bool cmp(node aa,node bb) 39 { 40 return aa.d < bb.d; 41 } 42 43 double solve(int k) 44 { 45 init(n); 46 47 int p[20],cnt = 0; 48 int num = 0; 49 50 for (int i = 0;i < n;i++) 51 { 52 if (k & (1 << i)) p[cnt++] = i; 53 } 54 55 for (int i = 0;i < cnt;i++) 56 { 57 for (int j = i + 1;j < cnt;j++) 58 { 59 g[num].x = p[i]; 60 g[num].y = p[j]; 61 g[num].d = a[p[i]][p[j]]; 62 num++; 63 } 64 } 65 66 int sum = 0,sm = 0; 67 68 for (int i = 0;i < cnt;i++) 69 { 70 int t = p[i]; 71 sum += b[t]; 72 } 73 74 sort(g,g+num,cmp); 75 76 for (int i = 0;i < num;i++) 77 { 78 int x = g[i].x,y = g[i].y; 79 80 //printf("%d %d88\n",x,y); 81 82 if (fin(x) == fin(y)) continue; 83 84 unit(x,y); 85 86 sm += g[i].d; 87 } 88 89 return 1.0 * sm / sum; 90 } 91 92 int main() 93 { 94 while (scanf("%d%d",&n,&m) != EOF) 95 { 96 double minn = 10000000000; 97 98 if (!m && !n) break; 99 100 101 for (int i = 0;i < n;i++) 102 scanf("%d",&b[i]); 103 104 for (int i = 0;i < n;i++) 105 for (int j = 0;j < n;j++) 106 scanf("%d",&a[i][j]); 107 108 int ba = (1 << n) - 1; 109 110 for (int i = 3;i <= ba;i++) 111 { 112 int num = 0; 113 114 for (int j = 0;j < n;j++) 115 { 116 if (i & (1 << j)) num++; 117 } 118 119 if (num == m) 120 { 121 //0printf("00\n"); 122 double tmp = solve(i); 123 124 if (tmp < minn) 125 { 126 minn = tmp; 127 } 128 } 129 } 130 131 int mark; 132 133 for (int i = 3;i <= ba;i++) 134 { 135 int num = 0; 136 137 for (int j = 0;j < n;j++) 138 { 139 if (i & (1 << j)) num++; 140 } 141 142 if (num == m) 143 { 144 double tmp = solve(i); 145 146 if (tmp == minn) 147 { 148 mark = i; 149 break; 150 } 151 } 152 } 153 154 int p[20]; 155 156 int cnt = 0; 157 158 for (int i = 0;i < n;i++) 159 { 160 if (mark & (1 << i)) p[cnt++] = i; 161 } 162 163 for (int i = 0;i < cnt;i++) 164 { 165 if (!i) printf("%d",p[i]+1); 166 else printf(" %d",p[i]+1); 167 } 168 169 printf("\n"); 170 } 171 172 return 0; 173 }
再附上一份t了的代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #include <map> 5 #include <vector> 6 using namespace std; 7 8 int n,m; 9 int num = 0; 10 int par[20]; 11 int a[20]; 12 int b[20][20]; 13 bool v[20]; 14 int s[20]; 15 vector<int> vv[10005]; 16 map<double,int> mmp; 17 18 double minn; 19 20 struct node 21 { 22 int x,y,d; 23 } g[500]; 24 25 bool cmp(node aa,node bb) 26 { 27 return aa.d < bb.d; 28 } 29 30 void init(int k) 31 { 32 for (int i = 0;i <= k;i++) 33 par[i] = i; 34 } 35 36 int fin(int x) 37 { 38 if (x == par[x]) return x; 39 else return par[x] = fin(par[x]); 40 } 41 42 void unit(int x,int y) 43 { 44 x = fin(x); 45 y = fin(y); 46 47 if (x != y) par[x] = y; 48 } 49 50 void solve(void) 51 { 52 int cnt = 0; 53 54 bool f = 0; 55 56 init(n); 57 58 for (int i = 0;i < m;i++) 59 for (int j = i + 1;j < m;j++) 60 { 61 int x = s[i],y = s[j]; 62 if (b[x][y]) 63 { 64 g[cnt].x = x; 65 g[cnt].y = y; 66 g[cnt].d = b[x][y]; 67 cnt++; 68 } 69 } 70 71 int sum = 0; 72 73 for (int i = 0;i < m;i++) 74 { 75 int t = s[i]; 76 77 sum += a[t]; 78 } 79 80 sort(g,g+cnt,cmp); 81 82 int sm = 0; 83 84 for (int i = 0;i < cnt;i++) 85 { 86 int x = g[i].x,y = g[i].y; 87 88 if (fin(x) == fin(y)) continue; 89 90 sm += g[i].d; 91 92 unit(x,y); 93 } 94 95 int rt = fin(s[0]); 96 97 for (int i = 0;i < m;i++) 98 { 99 if (fin(s[i]) != fin(rt)) f = 1; 100 } 101 102 double now = 1.0 * sm / sum; 103 104 if (!f && now < minn) 105 { 106 if (!mmp[now]) 107 { 108 mmp[now] = num; 109 minn = now; 110 111 for (int i = 0;i < m;i++) 112 vv[num].push_back(s[i]); 113 114 num++; 115 } 116 117 } 118 } 119 120 void dfs(int i,int p) 121 { 122 if (m == n && p == m - 1) 123 { 124 s[p] = i; 125 solve(); 126 return; 127 } 128 else if (m < n && p == m) 129 { 130 solve(); 131 return; 132 } 133 134 s[p] = i; 135 136 for (int j = 0;j < n;j++) 137 { 138 if (!v[j]) 139 { 140 v[j] = 1; 141 dfs(j,p+1); 142 v[j] = 0; 143 } 144 } 145 } 146 147 148 int main() 149 { 150 while (scanf("%d%d",&n,&m) != EOF) 151 { 152 if (m == 0 && n == 0) break; 153 154 num = 0; 155 156 minn = 1000000000; 157 158 memset(v,0,sizeof(v)); 159 memset(s,0,sizeof(s)); 160 memset(a,0,sizeof(a)); 161 memset(b,0,sizeof(b)); 162 memset(g,0,sizeof(g)); 163 memset(vv,0,sizeof(vv)); 164 165 for (int i = 0;i < n;i++) 166 scanf("%d",&a[i]); 167 168 169 for (int i = 0;i < n;i++) 170 for (int j = 0;j < n;j++) 171 scanf("%d",&b[i][j]); 172 173 for (int i = 0;i < n;i++) 174 { 175 v[i] = 1; 176 dfs(i,0); 177 v[i] = 0; 178 } 179 180 int k = mmp[minn]; 181 182 sort(vv[k].begin(),vv[k].end()); 183 184 for (int i = 0;i < vv[k].size();i++) 185 { 186 if (!i) printf("%d",vv[k][i] + 1); 187 else printf(" %d",vv[k][i] + 1); 188 } 189 190 printf("\n"); 191 } 192 193 return 0; 194 }
康复训练中~欢迎交流!