UVA 1151 Buy or Build (最小生成树)

来源:互联网 发布:华为视频会议软件下载 编辑:程序博客网 时间:2024/05/15 21:50

题意:

告诉你n 个点的坐标,你要在两个点之间连线,使得点全部相同,连边的费用为这两个点的欧几里得距离,你的目的是使这个费用最低,并且你有q(q <= 8) 个套餐可以用,一个套餐中会告诉你一些点已经连通, 问最少花费?

思路:

全部的点相通,很明显是最小生成树。

最容易想到的是,暴力枚举哪一个套餐用,哪一个套餐不用,在求最小生成树,这样会超时,因为原图是一个完全图,有100W个边。

有个小优化:

我们可以先求一边最小生成树,n-1个边,在n-1个边中在暴力枚举套餐。 这样边少了很多很多。

暴力枚举套餐,可以用二进制枚举子集的方法。

#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <cmath>#include <cstdlib>#define Siz(x) (int)x.size()#define Max(a,b)((a)>(b)?(a):(b))#define Min(a,b)((a)>(b)?(b):(a))#define ps push_back#define sqr(x)((x)*(x))using namespace std;const int maxn = 1000 + 7;const int inf = 0x3f3f3f3f;typedef long long LL;int T, n, q, num_edge;vector<int>c[10];int w[10],fa[maxn];//double dist[maxn][maxn];struct Node{    int x, y;    void read(){        scanf("%d %d",&x, &y);    }}nod[maxn];struct edge{    int f,t;    int d;    int flag;    bool operator < (const edge& rhs) const {        return d < rhs.d;    }}p[maxn*maxn];void addedge(int x,int y,int d){    p[num_edge].f = x;    p[num_edge].t = y;    p[num_edge].flag = 0;    p[num_edge++].d = d;}void DIST(){    num_edge = 0;    for (int i = 1; i <= n; ++i){        for (int j = i+1; j <= n; ++j){            int t = (sqr(nod[j].y-nod[i].y) + sqr(nod[j].x-nod[i].x));            addedge(i,j,t);        }    }}int find(int x){    return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);}void add(int x,int y){    int fx = find(x);    int fy = find(y);    if (fx != fy){        fa[fx] = fy;    }}bool cmp(const edge& lhs, const edge& rhs){    return lhs.flag > rhs.flag;}int solve(int bin){    if (bin == n-1) return 0;    int ans = 0;    sort(p,p+num_edge);    for (int i = 0; i < num_edge; ++i){        int u = p[i].f;        int v = p[i].t;        if (find(u) != find(v)){            add(u,v);            ans += p[i].d;            bin++;            if (bin == n-1)break;        }    }    return ans;}int main(){    scanf("%d",&T);    int ks = 0;    while(T--){        scanf("%d %d",&n, &q);        LL ans = 0;        for (int i = 0; i < 10; ++i)c[i].clear();        for (int i = 1; i <= q; ++i){            int x,y;scanf("%d",&x);            scanf("%d",w+i);            for (int j = 0; j < x; ++j) {                scanf("%d",&y);                c[i].ps(y);            }        }        for (int i = 1; i <= n; ++i){            nod[i].read();        }        if (ks++)puts("");        DIST();        sort(p,p+num_edge);        int bin = 0;        for (int i = 1; i <= n; ++i)fa[i] = i;        for (int i = 0; i < num_edge; ++i){            int u = p[i].f;            int v = p[i].t;            if (find(u) != find(v)){                add(u,v);                ans += p[i].d;                p[i].flag = 1;                bin++;//                printf(" == %d %d\n",u,v);                if (bin == n-1)break;            }            else p[i].flag = 0;        }        sort(p,p+num_edge,cmp);        num_edge = n-1;        for (int i = 0; i < (1<<q); ++i){            int tmp = i;            LL sum = 0;            int bin2 = 0;            for (int j = 1; j <= n; ++j)fa[j] = j;            for (int j = 0; j < q; ++j){                int id = q-j;                if (tmp & 1){                    for (int k = 1; k < Siz(c[id]); ++k){                        if (find(c[id][k-1]) != find(c[id][k])){                            addedge(c[id][k-1],c[id][k],inf);                            add(c[id][k-1],c[id][k]);                            bin2++;                        }                    }                    sum += w[id];                }                tmp/=2;            }            sum += solve(bin2);            ans = Min(ans,sum);            num_edge = n-1;        }        printf("%lld\n",ans);    }    return 0;}/**17 32 4 1 23 3 3 6 73 9 2 4 50 24 02 04 21 30 54 4ans = 17**/


0 0
原创粉丝点击