hdu 2489 hdu1598 依旧最小生成树

hdu2489

求一个图中的一颗子树,使得Sum(edge weight)/Sum(point weight)最小~

数据量很小,暴力枚举,只是要注意精度,否则WA~

dfs暴力枚举C(M,N)种情况。

枚举出这M个点之后,Sum(point weight)固定,进行prime或者Kruskal使Sum(edge weight)求最小。

View Code
 1 #include <math.h>
 2 #include <stdio.h>
 3 #include <string.h>
 4 const int N=20;
 5 const int inf=10000000;
 6 int w[N];//用于记录每个点的权值
 7 int ans[N];//用于记录答案点
 8 int node[N];//用于记录临时的枚举的m个点
 9 int map[N][N],f[N][N];
10 int n,m;
11 double res;
12 int vis[N*(N+1)/2];//用于prime算法
13 int dis[N*(N+1)/2];//用于prime算法
14 int Prime(){
15     int i,j,t;
16     memset(vis,0,sizeof(vis));
17     for(i=1;i<=m;i++){
18        if(i==1) dis[i]=0;
19        else dis[i]=map[1][i];
20     }
21     int loc,sum=0;
22     for(i=1;i<=m;i++){
23        int min=inf;
24        for(j=1;j<=m;j++){
25            if(!vis[j]&&dis[j]<min){
26                min=dis[j];
27                loc=j;
28            }
29        }
30        vis[loc]=1;
31        sum+=min;
32        for(j=1;j<=m;j++){
33            if(!vis[j]&&map[loc][j]<dis[j]){
34                dis[j]=map[loc][j];
35            }
36        }
37     }
38     return sum;
39 }
40 void dfs(int u,int cnt){
41     int i,j;
42     node[cnt]=u;
43     if(cnt>=m){
44         for(i=1;i<=m;i++)
45             for(j=1;j<=m;j++)
46                 map[i][j]=f[node[i]][node[j]];
47         double sumEdge=1.0*Prime();
48         double sumPoint=0;
49         for(i=1;i<=m;i++){
50             sumPoint+=w[node[i]];
51         }
52         double sum=sumEdge/sumPoint;
53         if(sum-res<-(1e-8)){
54             res=sum;
55             for(i=1;i<=m;i++)
56             ans[i]=node[i];
57         }
58         return ;
59     }
60 
61     for(i=u+1;i<=n;i++)
62         dfs(i,cnt+1);
63 }
64 int main(){
65     int i,j;
66     while(scanf("%d %d",&n,&m)!=EOF){
67         if(n==0&&m==0) break;
68         for(i=1;i<=n;i++){
69             scanf("%d",&w[i]);
70         }
71         for(i=1;i<=n;i++)
72             for(j=1;j<=n;j++)
73                 scanf("%d",&f[i][j]);
74 
75         res=inf;
76         for(i=1;i<=n;i++)
77             dfs(i,1);
78 
79         for(i=1;i<m;i++)
80             printf("%d ",ans[i]);
81         printf("%d\n",ans[i]);
82     }
83     return 0;
84 }

hdu1598

最小生成树变形

给两个点求出从start到end的一条路径,满足权值最大的边-权值最小的边的差最小~

或者说是贪心+并查集吧:

思路如下:将所有的边按照权值大小排序,然后从第一条边开始枚举,每次枚举都按照kruskal寻找一直到start和end在一个集合里了,

就不用继续合并了,此时用最后加入的边-枚举的那条边,以此类推,找所有情况中的最小值。

依旧枚举~

View Code
 1 #include <stdio.h>
 2 #include <vector>
 3 #include <string.h>
 4 #include <iostream>
 5 #include <algorithm>
 6 using namespace std;
 7 const int N=205;
 8 const int inf=100000000;
 9 int n,m,q;
10 int start,end;
11 int father[N];
12 struct edge{
13     int x,y,z;
14 }e[N];
15 int max(int a,int b){return a>b?a:b;}
16 int min(int a,int b){return a<b?a:b;}
17 int find(int x){
18     if(father[x]!=x)
19         father[x]=find(father[x]);
20     return father[x];
21 }
22 void merge(int a,int b){
23     int x=find(a);
24     int y=find(b);
25     if(x!=y)
26         father[x]=y;
27 }
28 int cmp(edge e1,edge e2){
29     return e1.z<e2.z;
30 }
31 void init(){
32     int i;
33     for(i=0;i<=n;i++){
34         father[i]=i;
35     }
36 }
37 int main(){
38     int i,j;
39     while(scanf("%d %d",&n,&m)!=EOF){
40         for(i=0;i<m;i++){
41             scanf("%d %d %d",&e[i].x,&e[i].y,&e[i].z);
42         }
43         sort(e,e+m,cmp);
44         scanf("%d",&q);
45         while(q--){
46             int _min=inf,res;
47             scanf("%d %d",&start,&end);
48             for(i=0;i<m;i++){
49                 init();
50                 res=inf;
51                 for(j=i;j<m;j++){
52                     merge(e[j].x,e[j].y);
53                     if(find(start)==find(end)){
54                         res=e[j].z-e[i].z;
55                     }
56                 }
57                 _min=min(res,_min);
58             }
59             if(_min==inf) _min=-1;
60             printf("%d\n",_min);
61         }
62     }
63     return 0;
64 }

 

posted @ 2013-01-22 02:12  _sunshine  阅读(974)  评论(0编辑  收藏  举报