Wikioi 1002

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
#define maxn 2600
#define INF 0xffffff
int father[maxn];

struct Map
{
    int x, y;
}map[maxn];

struct node
{
    int a, b, len;
    friend bool operator < (node x, node y)
    {
        return x.len > y.len;
    }
};

int find(int x);
int Union(int x, int y);
int Distance(Map a, Map b);
void kruskal(int n);

int main()
{
    int m, n;

    while(cin >> m >> n)
    {
        int i, j, k=0;
        char ch;

        for(i=1; i<=m; i++)
        for(j=1; j<=n; j++)
        {
            cin >> ch;

            if(ch == '#')
            {
                map[++k].x = i;
                map[k].y = j;
            }
        }

        for(i=1; i<=k; i++)
            father[i] = i;

        kruskal(k);
    }

    return 0;
}
int find(int x)
{
    if(father[x] != x)
        return father[x] = find(father[x]);
    return x;
}
int Union(int x, int y)
{
    x = find(x), y = find(y);

    if(x != y)
    {
        father[x] = y;
        return 1;
    }

    return 0;
}
int Distance(Map a, Map b)
{
    int dx = abs(a.x - b.x), dy = abs(a.y - b.y);

    if(dx <= 1 && dy <= 1)return 0;
    if(dx <= 1)return dy-1;
    if(dy <= 1)return dx-1;

    return INF;
}
void kruskal(int n)
{
    priority_queue<node> que;
    int i, j, k, sum=0, ans=0;
    node q;

    for(i=1; i<n; i++)
    for(j=i+1; j<=n; j++)
    {
        q.len = Distance(map[i], map[j]);
        if(q.len == 0)
            k = Union(i, j);
        else if(q.len != INF)
        {
            q.a = i, q.b = j;
            que.push(q);
        }
    }

    for(i=1; i<=n; i++)
        if(father[i] == i)
            ans++;
    k = 0;
    while(que.size())
    {
        q = que.top(), que.pop();

        if(Union(q.a, q.b))
        {
            sum += q.len;
            k++;
        }
    }

    cout << ans <<endl;
    cout << k << " " << sum <<endl;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值