UVALive-7303- Aquarium【最小生成树】【连通块】


UVALive - 7303- Aquarium


这里写图片描述
这里写图片描述

题目链接:7303

题目大意:给你一个r * c的格子,每个格子有一个 ‘ \ ’ 或者 ‘/’ 的墙,以及打掉墙的费用,问使得所有块联通的最小费用。(看图好理解)

题目思路:就是将他化成一个图,联通的块相当于一个点,两个点之间有一条边,边的权值为墙的费用。

转化为连通块的思路是:每个格子看成两部分,左侧和右侧。以一行来看,假设两个格子A,B。那么B格子的右侧的编号一定和A格子的左侧的编号相同。如图所示
这里写图片描述
给每个格子的左右侧标上号,然后加入边,边的两个端点为一个格子的两个编号。权值为墙的费用

然后处理行与行之间的边,稍微讨论一下,假设上边格子为A,下面格子为B。那么如果A是‘/’,B是’/’,那么A的右格子和B的左格子是相通的,这时候加一条边,将权值设为0就可以了。

注意数组大小!!!

以下是代码:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <functional>
#include <numeric>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <queue>
#include <deque>
#include <list>
using namespace std;

typedef long long ll;
string s[105];
int val[105][105];
struct node
{
    int a,b;
}g[105][105];
struct node2
{
    int a,b,len;
}edge[40005];
int fa[20005];
int kk;
//=======最小生成树====
void add(int u, int v,int w)
{
    edge[kk].a = u;
    edge[kk].b = v;
    edge[kk++].len = w;
}
bool cmp(node2 a,node2 b)
{
    return a.len < b.len;
}
int getfather(int v)
{
    return (fa[v] == v) ? v : fa[v] = getfather(fa[v]);
}
void merges(int x,int y)
{
    x = getfather(x);
    y = getfather(y);
    if (x != y) fa[x] = y;
}
//==============
int main()
{
    int t;
    cin >> t;
    int lllll = 1;
    while(t--)
    {
        int c,r;
        cin >> c >> r;
        kk = 0;
        for (int i = 0; i < c; i++)
        {
            cin >> s[i];
        }
        for (int i = 0; i < c; i++)
        {
            for (int j = 0; j < r; j++)
            {
                cin >> val[i][j];
            }
        }
        int p = 1;
        for (int i = 0; i < c; i++)
        {
            for (int j = 0; j < r; j++)
            {
                if (j == 0)
                {
                    g[i][j].a = p++;
                    g[i][j].b = p++;
                    add(g[i][j].a,g[i][j].b,val[i][j]);
                }
                else
                {
                    g[i][j].a = g[i][j - 1].b;
                    g[i][j].b = p++;
                    add(g[i][j].a,g[i][j].b,val[i][j]);
                }
                if (i != 0)
                {
                    if (s[i - 1][j] == '/')
                    {
                        if (s[i][j] == '/')
                        {
                            add(g[i][j].a,g[i - 1][j].b,0);
                        }
                        else
                        {
                            add(g[i][j].b,g[i - 1][j].b,0);
                        }
                    }
                    else
                    {
                        if (s[i][j] == '/')
                        {
                            add(g[i][j].a,g[i - 1][j].a,0);
                        }
                        else
                        {
                            add(g[i][j].b,g[i - 1][j].a,0);
                        }
                    }
                }
            }
        }
        for (int i = 1; i <= 20001; i++)
        {
            fa[i] = i;
        }
        sort(edge,edge + kk,cmp);
        int ans = 0;
        for (int i = 0; i < kk; i++)
        {
            int u = edge[i].a;
            int v = edge[i].b;
            if (getfather(u) != getfather(v))
            {
                merges(u,v);
                ans += edge[i].len;
            }
        }
        printf("Case %d: ",lllll++);
        cout << ans << endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值