zoukankan      html  css  js  c++  java
  • UVA 1151 Buy or Build MST(最小生成树)

    题意:

      在平面上有n个点,要让所有n个点都连通,所以你要构造一些边来连通他们,连通的费用等于两个端点的欧几里得距离的平方。另外还有q个套餐,可以购买,如果你购买了第i个套餐,该套餐中的所有结点将变得相互连通,第i个套餐的花费为ci。求最小花费。

    思路:

      在这里我们可以采取枚举所有可能 + K算法来得出答案,比如这里有三个套餐,我们利用二进制枚举 001、010、011 、100、 101、 110、 111 分别代表第一个和第二个不要,要第三个(001);不要第一个和第三个,要第二个(010).......即 0 代表不要, 1 代表要,然后把要的套餐中的所有点都连通,再用K算法求剩下的未连接的点的最小生成树。

    注意:

      在套餐中合并点时不能单纯地让pre[i] = pre[1](i > 1);pre[i]数组代表 pre[i] 和 i 在一个集合里面(并查集);举个栗子:

      有一个套餐是:

      4 10  2 3 4 5

      含义是购买这个套餐中可以让四个点连通,分别是2,3,4,5号点,费用为 10;如果让 pre[3] = pre[4]=pre[5] = 2;

      那么假设还有个套餐:

      3 9 1 5 3 

      含义如上 ,如果再写pre[5] = pre[3] = 1;那么假设我购买了这俩个套餐,本应该2 3 4 5 1都在一个集合里面的,但是按照上面那么写 则 2 4 是一个集合, 1 3 5 是一个集合。不符合我的意思,所以购买套餐合并里面的点时应该写成pre[i] = Find(pre[1]);前提是这俩个不在一个集合里面。

    代码:

      1 #include <bits/stdc++.h>  
      2 #define prln(x) cout<<(x)<<endl  
      3 using namespace std;  
      4 typedef long long LL;  
      5   
      6 const double PI = acos(-1);  
      7 const double ESP = 1e-8;  
      8 const int MAXN = 1000 + 3;  
      9 const int MOD = 1e9 + 7;  
     10 int pre[MAXN];  
     11   
     12 typedef struct Point{ //题目中给的点  
     13     int x;  
     14     int y;  
     15 }Po;  
     16   
     17 typedef struct Buy{  //套餐  
     18     int m;      //购买该套餐可以合并点的个数  
     19     int ci;       //购买该套餐的费用  
     20     int a[MAXN];   //这个套餐可以合并的点的编号  
     21     int flag;    //是否要购买这个套餐,对每个套餐的这个值进行二进制枚举  
     22 }Bu;  
     23   
     24 typedef struct City{   //用来存储图  
     25     int u;  
     26     int v;  
     27     int w;  
     28 }Ci;  
     29   
     30 Ci edge[MAXN * MAXN / 2 + 3];  
     31 Po pt[MAXN];  
     32 Bu buy[11];  
     33   
     34 int Find(int x) //并查集  
     35 {  
     36     return x == pre[x] ? x : pre[x] = Find(pre[x]);  
     37 }  
     38   
     39 void Stpre(int n)  
     40 {  
     41     for(int i = 0; i <= n; i++)  
     42         pre[i] = i;  
     43 } 
     44 
     45 void Ststu()
     46 {
     47         memset(&pt,0,sizeof(Po));
     48         memset(&buy,0,sizeof(Bu));
     49         memset(&edge,0,sizeof(Ci));
     50 }
     51 
     52 int Ojld(Point a, Point b)
     53 {
     54     int xx = a.x - b.x;
     55     int yy = a.y - b.y;
     56     return xx * xx + yy *yy;
     57 }
     58 
     59 int mycmp(City a, City b)
     60 {
     61     return a.w < b.w;
     62 }
     63 
     64 int ksu(int l)//K算法
     65 {
     66     int ans= 0;
     67     for(int i = 1; i<= l; i++)
     68     {
     69         int fv = Find(edge[i].v);
     70         int fu = Find(edge[i].u);
     71         if(fu != fv)
     72         {
     73             pre[fu] = pre[fv];
     74             ans += edge[i].w;
     75         }
     76     }
     77     return ans;
     78 }
     79 
     80 int main()
     81 {
     82     //freopen("input.txt","r",stdin);
     83     int t;
     84     cin >> t;
     85     while(t--)
     86     {
     87         Ststu();
     88         int n, q;
     89         scanf("%d%d",&n, &q);
     90         for(int i = 1; i <= q; i++)
     91         {
     92             scanf("%d",&buy[i].m);
     93             scanf("%d",&buy[i].ci);
     94             for(int j = 1; j <= buy[i].m; j++)
     95                 scanf("%d",&buy[i].a[j]);
     96         }
     97         for(int i = 1; i <= n; i++)
     98             scanf("%d%d",&pt[i].x, &pt[i].y);
     99         int sum = 0;
    100         for(int i = 1; i < n; i++)
    101         {
    102             for(int j = i + 1; j <= n; j++)
    103             {
    104                 sum++;
    105                 edge[sum].u = i;
    106                 edge[sum].v = j;
    107                 edge[sum].w = Ojld(pt[i], pt[j]);
    108                 //printf("%d %d %d %d
    ",sum,i,j,edge[sum].w);
    109             }
    110         }
    111         sort(edge + 1, edge + sum + 1 , mycmp);
    112 
    113         int ans =  0x7F7F7F7F;
    114         for(int i = 0; i < (1 << q); i++) //二进制枚举
    115         {
    116             Stpre(n);
    117             int temp = i;
    118             int mst = 0;
    119             for(int j = 1; j <= q; j++)
    120             {
    121                 if(temp & 1)
    122                 {
    123                     mst += buy[j].ci;
    124                     for(int k = 2; k <= buy[j].m; k++)
    125                     {
    126                         int fx = Find ( buy[j].a[1] );
    127                         int fy = Find( buy[j].a[k] );
    128                         if(fy != fx)
    129                           pre[fy] = pre[fx];
    130                     }
    131                 }
    132                 temp >>= 1;
    133             }
    134             mst += ksu(sum);
    135             ans = min(ans, mst);
    136         }
    137         printf("%d
    ",ans);
    138         if(t)prln("");
    139     }
    140     return 0;
    141 }


    
    
  • 相关阅读:
    获取非行间样式
    获取非行间样式
    prompt 方法显示输入对话框
    comfirm 方法显示对话框
    移动端页面常见问题及解决方案
    原生js怎样获取后台端口数据
    canvas描绘渐变的矩形
    cookie 的增加,销毁,读取
    canvas 绘制图形
    数组的排序,去重复
  • 原文地址:https://www.cnblogs.com/Ash-ly/p/5397638.html
Copyright © 2011-2022 走看看