zoukankan      html  css  js  c++  java
  • 【最小生成树+子集枚举】Uva1151 Buy or Build

    Description

    平面上有n个点(1<=N<=1000),你的任务是让所有n个点连通,为此,你可以新建一些边,费用等于两个端点的欧几里得距离的平方。

    另外还有q(0<=q<=8)个套餐,可以购买,如果你购买了第i个套餐,该套餐中的所有结点将变得相互连通,第i个套餐的花费为ci。

    求最小花费。

    Solution

    对于套餐可以用子集枚举处理,求最小生成树时只需考虑原图是最小生成树中的边。

    正确性可以按Kruskal过程,以前被舍弃的边选了套餐后依然会被舍弃。

    Code

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #define ll long long
     5 using namespace std;
     6 const int maxn=1005;
     7 
     8 int x[maxn],y[maxn],p[maxn];
     9 int find(int x){return p[x]==x?x:p[x]=find(p[x]);}
    10 struct edge{
    11     int u,v,w;
    12     bool operator<(const edge&a)
    13      const {return w<a.w;}
    14 }_e[maxn*maxn],e[maxn];
    15 int dist(int a,int b){
    16     return (x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]);
    17 }
    18 int q[8][maxn],c[8],t[8];
    19 int n,m,r,cnt;
    20 
    21 void clear(){
    22     m=cnt=0;
    23 }
    24 
    25 ll solve(){
    26     ll ret=0;
    27     for(int i=1;i<n;i++){
    28         int x=find(e[i].u),y=find(e[i].v);
    29         if(x!=y){
    30             ret+=e[i].w;
    31             p[x]=y;
    32         }
    33     }
    34     return ret;
    35 }
    36 
    37 int main(){
    38     int T;
    39     scanf("%d",&T);
    40     
    41     while(T--){
    42         clear();
    43         scanf("%d%d",&n,&r);
    44         for(int i=0;i<r;i++){
    45             scanf("%d%d",&t[i],&c[i]);
    46             for(int j=1;j<=t[i];j++)
    47                 scanf("%d",&q[i][j]);
    48         }
    49         
    50         for(int i=1;i<=n;i++)
    51             scanf("%d%d",&x[i],&y[i]),p[i]=i;
    52         
    53         for(int i=1;i<=n;i++)
    54             for(int j=i+1;j<=n;j++)
    55             _e[++m]=(edge){i,j,dist(i,j)};
    56         sort(_e+1,_e+m+1);
    57         
    58         ll ans=0;
    59         for(int i=1;i<=m;i++){
    60             int x=find(_e[i].u),y=find(_e[i].v);
    61             if(x!=y){
    62                 e[++cnt]=_e[i];
    63                 ans+=_e[i].w;
    64                 p[x]=y;
    65             }
    66         }
    67         
    68         for(int S=0;S<(1<<r);S++){
    69             ll ansx=0;
    70             for(int i=1;i<=n;i++) p[i]=i;
    71             
    72             for(int i=0;i<r;i++)
    73                 if(S&(1<<i)){
    74                     ansx+=c[i];
    75                     for(int j=2;j<=t[i];j++)
    76                         p[find(q[i][j-1])]=find(q[i][j]);
    77                 }
    78             ansx+=solve();
    79             ans=min(ans,ansx);
    80         }
    81         printf("%lld
    ",ans);
    82         if(T) printf("
    ");
    83     }
    84     return 0;
    85 }
  • 相关阅读:
    int、bigint、smallint 和 tinyint
    我的fedora9安装后配置
    系统引导设置与管理EasyBCD与VistaBootPRO
    从Xml文档内部引用Xml Schema验证
    linux开机顺序
    OS引导-笔记
    Logic Volume笔记
    Service笔记
    python中若类属性与实例属性同名
    解析JavaScript中的null与undefined
  • 原文地址:https://www.cnblogs.com/xkui/p/4562900.html
Copyright © 2011-2022 走看看