uva 1151 买还是建

来源:互联网 发布:天才麻将少女知乎 编辑:程序博客网 时间:2024/05/01 10:28
题意:给n个点和每个点的坐标,q个套餐,要求n个点联通,q个套餐内可以花费c来使得所有套餐内给出的点都联通,否则需要计算点之间的欧几里得距离。这里的欧几里得距离不用开平方。

思路:紫书上的题,先用kruskal求一遍最小生成树,然后枚举所有套餐的情况,每选用一个套餐,把套餐内的点之间的距离变为0(可以直接用并查集把这两个点合起来),维护最小值。

#include<cstdio>#include<algorithm>#include<cstring>#define ll long longusing namespace std;const int maxn=1005;int x[maxn],y[maxn],p[maxn];int q[8][maxn],c[8],t[8];int n,m,r;struct Edge{    int u,v,w;    bool operator<(const Edge &a)const{        return w < a.w;    }} edge[maxn*maxn],re_edge[maxn];int dist(int x1,int y1,int x2,int y2){    return (x1 - x2)*(x1 - x2) + (y1-y2)*(y1-y2);}int find(int x){    return p[x]==x?x:p[x]=find(p[x]);}ll Kruskal(int n,int m){    sort(edge,edge+m);    for(int i =1; i<=n; i++) p[i]=i;    int cnt = 0;    ll ans = 0;    for(int i=0; i < m; i++)    {        int x=find(edge[i].u),y=find(edge[i].v);        if(x!=y){            re_edge[cnt++]=edge[i];            ans+=edge[i].w;            p[x]=y;        }        if(cnt == n -1) break;    }    if(cnt < n-1) ans = -1;    return ans;}ll re_Kruskal(){    ll ans=0;    for(int i=0; i < n-1; i++){        int x=find(re_edge[i].u),y=find(re_edge[i].v);        if(x!=y){            ans+=re_edge[i].w;            p[x]=y;        }    }    return ans;}int main(){    //freopen("in.txt","r",stdin);    int T;    scanf("%d",&T);    while(T--)    {        m = 0;        scanf("%d%d",&n,&r);        for(int i=0; i<r; i++){            scanf("%d%d",&t[i],&c[i]);            for(int j=1; j<=t[i];j++)                scanf("%d",&q[i][j]);        }        for(int i=1; i<=n; i++)            scanf("%d%d",&x[i],&y[i]);        for(int i=1; i<=n; i++){            for(int j=i+1; j<=n; j++){                edge[m].u = i;                edge[m].v = j;                edge[m++].w = dist(x[i],y[i],x[j],y[j]);            }        }        ll ans= Kruskal(n,m);//先找出最小生成树        for(int s=0; s<(1<<r); s++)        {            ll tans=0;            for(int i=1; i<=n; i++) p[i]=i;            for(int i=0; i<r; i++){                if((s >> i)&1)                {                    tans+=c[i];                    for(int j=2; j<=t[i]; j++)                        p[find(q[i][j-1])]=find(q[i][j]);                }            }            tans+=re_Kruskal();            ans=min(ans,tans);        }        printf("%lld\n",ans);        if(T) printf("\n");    }    return 0;}


0 0
原创粉丝点击