码迷,mamicode.com
首页 > 其他好文 > 详细

UVA 1151

时间:2016-11-13 11:41:39      阅读:186      评论:0      收藏:0      [点我收藏+]

标签:while   double   注意   freopen   计算   space   联通   style   str   

/*
    题意:有n个点,现在需要联通所有,有q种套餐可以选择,
    当然套餐之外也可以自己添加边,意为达到最短距离。

    
    题意很明显,不知道需要使用哪一种套餐,
    那么需要枚举每一种套餐的情况。
    然后再进行对比。
    注意最开始没有套餐的情况。
*/

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

const int maxn = 1100;

class Cor
{
public:
    int x,y;
}cor[maxn];             //坐标

class Node
{
public:
    int x,y;
    int dis;
}edge[maxn*maxn];       //

vector<int>t[10];
int cost[10];   //每中套餐的花费
int n,m,q;
int f[maxn];

bool cmp(Node a,Node b)
{
    return a.dis < b.dis;
}

double distances(Cor a,Cor b)
{
    int dx = a.x - b.x;
    int dy = a.y - b.y;
    return (dx*dx + dy*dy);
}

void inti(int n)
{
    for(int i = 0;i <= n; i++)
        f[i] = i;
    return ;
}

int Find(int x)
{
    int r = x;
    while(r != f[r])
        r = f[r];
    int i = x,j;
    while(f[i] != r){
        j = f[i];
        f[i] = r;
        i = j;
    }
    return r;
}

int merge(int x,int y)
{
    int a = Find(x);
    int b = Find(y);
    if(a == b)
        return false;
    else
        f[a] = b;
    return true;
}

int kruskal()       //标准的kruskal
{
    int pos = 0,sum = 0;       
    for(int i = 0;i < m && pos < n - 1; i++){
        if(merge(edge[i].x,edge[i].y)){
            pos++;
            sum += edge[i].dis;
        }
    }
    return sum;
}

void solve()
{
    inti(n);
    int ans = kruskal();            //初始的情况
    for(int i = 0;i < (1<<q); i++){
        int money = 0;
        inti(n);
        for(int j = 0;j < q; j++){  //枚举每一种套餐的情况
         //   if((i>>j)&1) continue;
            if(i&(1<<j)){
                money += cost[j];
                for(int k = 1;k < t[j].size(); k++){
                    merge(t[j][k],t[j][0]); //把套餐的点相连
                }
            }
        }
        ans = min(ans,kruskal() + money);
    }
    printf("%d\n",ans);
    return ;
}

int main()
{
   // freopen("in.txt","r",stdin);
    int ncase,pn = 1;
    scanf("%d",&ncase);
    while(ncase--){
        if(pn > 1)      //UVA的输出
            printf("\n");
        pn++;
        for(int i = 0;i < 10; i++)  //要清理,初始化
            t[i].clear();
        scanf("%d%d",&n,&q);
        for(int i = 0;i < q; i++){  //vector是把每一种套餐记录,
            //            因为不知道每一种套餐有几个点,所以用vector很合适
            int num,temp;
            scanf("%d%d",&num,&cost[i]);
            for(int j = 0;j < num; j++){
                scanf("%d",&temp);
                t[i].push_back(temp);
            }
        }
        for(int i = 1;i <= n; i++)
            scanf("%d%d",&cor[i].x,&cor[i].y);
        m = 0;
        for(int i = 1;i <= n; i++){
            for(int j = i + 1;j <= n; j++){
                edge[m].x = i;
                edge[m].y = j;
                edge[m++].dis = distances(cor[i],cor[j]);//计算每一条边的长度
            }
        }
        sort(edge,edge+m,cmp);  //kruskal特有
        solve();
    }
    return 0;
}

 

UVA 1151

标签:while   double   注意   freopen   计算   space   联通   style   str   

原文地址:http://www.cnblogs.com/Since-natural-ran/p/6058235.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!