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

题目连接:https://vjudge.net/problem/UVA-1151

思路:先记录下不用任何方案最小生成树的边,然后枚举方案,选择某些方案后的剩下要选的边肯定在不用任何方案的最小生成树里选,枚举所有方案的方法值得学习一下

#include <bits/stdc++.h>
using namespace std;
vector<int> pl[10];
int cost[10],x[1005],y[1005],pre[1005];
int medge[1005];
struct node
{
    int u,v,dis;
    bool operator < (const struct node a) const
    {
        return dis < a.dis;
    }
}edge[1005 * 1005];

inline int dist(int i,int j)
{
    return (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);
}
inline int findset(int x)
{
    if(x == pre[x]) return x;
    else return pre[x] = findset(pre[x]);
}
inline bool join(int x,int y)
{
    int fx,fy;
    fx = findset(x),fy = findset(y);
    if(fx != fy) {
        pre[fy] = fx;
        return true;
    }
    return false;
}
inline void init(int n)
{
    for(int i = 1; i <= n; ++i) {
            pre[i] = i;
    }
}
int main(void)
{
    int T,n,num,cnt,temp,edge_cnt,ans,anss,flag = 0;
    scanf("%d",&T);
    while(T--) {
        scanf("%d %d",&n,&num);
        for(int i = 0; i < num; ++i) {
            scanf("%d %d",&cnt,&cost[i]);
            pl[i].clear();
            while(cnt--) {
                scanf("%d",&temp);
                pl[i].push_back(temp);
            }
        }
        for(int i = 1; i <= n; ++i) {
            scanf("%d %d",&x[i],&y[i]);
        }
        edge_cnt = 0;

        for(int i = 1; i <= n; ++i) {
            for(int j = i + 1; j <= n; ++j) {
                edge[edge_cnt].u = i;
                edge[edge_cnt].v = j;
                edge[edge_cnt].dis = dist(i,j);
                edge_cnt++;
            }
        }
        sort(edge,edge + edge_cnt);
        cnt = 0;
        ans = 0;
        init(n);
        for(int i = 0; i < edge_cnt; ++i) {
            if(join(edge[i].u,edge[i].v)) {
                medge[cnt] = i;
                ans += edge[i].dis;
                cnt++;
            }
            if(cnt == n - 1) break;
        }
        for(int i = 0;i < (1 << num); ++i) {
            init(n);
            anss = 0,cnt = 0;
            for(int j = 0; j < num; ++j) {
                if(i & (1 << j)) {
                    temp = pl[j][0];
                    anss += cost[j];
                    for(int k = 1; k < pl[j].size(); k++) {
                        if(join(pl[j][k],temp)) cnt++;
                    }
                }
            }
            for(int j = 0; j <= n - 1; ++j) {
                if(join(edge[medge[j]].u,edge[medge[j]].v)) {
                    anss += edge[medge[j]].dis;
                    cnt++;
                }
                if(cnt == n - 1) break;
            }
            ans = min(ans,anss);
        }
        if(flag) {
            printf("\n");
        }
        flag = 1;
        printf("%d\n",ans);
    }
    return 0;
}
/*
1
7 3
2 4 1 2
3 3 3 6 7
3 9 2 4 5
0 2
4 0
2 0
4 2
1 3
0 5
4 4
*/

猜你喜欢

转载自blog.csdn.net/GYH0730/article/details/81675292
今日推荐