[最小生成树+二进制枚举]UVa1151 - Buy or Build

来源:互联网 发布:罗技键盘推荐 知乎 编辑:程序博客网 时间:2024/05/17 04:07

二进制枚举子集不太懂

用的还是例题的思路

#include<bits/stdc++.h>using namespace std;const int maxn = 1005;struct point {    int x,y;}pp[maxn];struct edge{    int s,e,dist;}l[maxn*maxn];int q,n,m;int p[maxn];vector<int> g[10];int c[10];int distance_(point a,point b){    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);}int cmp(edge a,edge b){    return a.dist < b.dist;}int find_(int x){    return p[x]==x?x:p[x]=find_(p[x]);}bool merge_(int a,int b){    int x=find_(a);    int y=find_(b);    if(x==y) return false;    p[x]=y;    return true;}int kruskal(){    int ans=0;    int num=0;    for(int i=0;i<m&&num<n-1;i++){        if(merge_(l[i].s,l[i].e)){            num++;            ans+=l[i].dist;        }    }    return ans;}void solve(){    for(int i=0;i<=n;i++) p[i]=i;    int ans=kruskal();    for(int s=1;s<(1<<q);s++){        int cost=0;        for(int tt=0;tt<=n;tt++) p[tt]=tt;        for(int j=0;j<q;j++)        {            if(!((s>>j)&1)) continue;            cost+=c[j];            for(int k=0;k<g[j].size();k++)            {                merge_(g[j][k],g[j][0]);            }        }        ans=min(ans,cost + kruskal());    }    printf("%d\n",ans);}int main(){    int t;    scanf("%d",&t);    while(t--){        scanf("%d%d",&n,&q);        for(int i=0;i<10;i++) g[i].clear();        for(int i=0;i<q;i++){            int cnt=0;            scanf("%d%d",&cnt,&c[i]);            int a;            for(int j=0;j<cnt;j++){                scanf("%d",&a);                g[i].push_back(a);            }        }        for(int i=1;i<=n;i++){            scanf("%d%d",&pp[i].x,&pp[i].y);        }        m=0;        for(int i=1;i<=n;i++){            for(int j=i+1;j<=n;j++)            {                l[m].s=i;                l[m].e=j;                l[m++].dist=distance_(pp[i],pp[j]);            }        }        sort(l,l+m,cmp);        solve();        if(t) printf("\n");    }    return 0;}


0 0