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;
    }
}
时间: 2024-10-13 12:34:01

UVALive-7303- Aquarium【最小生成树】【连通块】的相关文章

BZOJ 2730:[HNOI2012]矿场搭建(割点+连通块)

[HNOI2012]矿场搭建 Description 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口.请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数.Input 输入文件有若干组数据,每组数据的第一行是一个正整数 N(N≤500),表示工地的隧道数,接下来的 N 行每行是用空

UVA 572 油田连通块-并查集解决

题意:8个方向如果能够连成一块就算是一个连通块,求一共有几个连通块. 分析:网上的题解一般都是dfs,但是今天发现并查集也可以解决,为了方便我自己理解大神的模板,便尝试解这道题目,没想到过了... 1 #include <cstdio> 2 #include <iostream> 3 #include <sstream> 4 #include <cmath> 5 #include <cstring> 6 #include <cstdlib&

洛谷P1141 //bfs求无向图的子连通块大小(多次询问)

http://www.luogu.org/problem/show?pid=1141 多询问题,求无向图的子连通块大小. 直接bfs,读一个搜一个,过60: 100%的点1,000,000个点,100,000次询问,显然是记忆化. 我很弱,最开始开了个数组记录每个点属于的连通块的第一个点的坐标,然后写了一堆,自己都烦. 后来问某大神,似拨开云雾见到了青天.用cnt记录连通块的" 名字 ". 学会了这一招,不代表过了. 我还是读一个点,如果访问过就输出,没访问就dfs,然后每dfs就循环

nyoj27-水池数目 (求连通块数目)【dfs】

http://acm.nyist.net/JudgeOnline/problem.php?pid=27 水池数目 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 南阳理工学院校园里有一些小河和一些湖泊,现在,我们把它们通一看成水池,假设有一张我们学校的某处的地图,这个地图上仅标识了此处是否是水池,现在,你的任务来了,请用计算机算出该地图中共有几个水池. 输入 第一行输入一个整数N,表示共有N组测试数据每一组数据都是先输入该地图的行数m(0<m<100)与列数n(0

CSUOJ 1601 War (离线并查集求连通块个数)

1601: War Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 130  Solved: 38 [Submit][Status][Web Board] Description AME decided to destroy CH's country. In CH' country, There are N villages, which are numbered from 1 to N. We say two village A and B ar

dfs:连通块

*/--> pre.src {background-color: Black; color: White;} pre.src {background-color: Black; color: White;} pre.src {background-color: Black; color: White;} pre.src {background-color: Black; color: White;} pre.src {background-color: Black; color: White;}

DFS(连通块) HDU 1241 Oil Deposits

题目传送门 1 /* 2 DFS:油田问题,一道经典的DFS求连通块.当初的难题,现在看上去不过如此啊 3 */ 4 /************************************************ 5 Author :Running_Time 6 Created Time :2015-8-4 10:11:11 7 File Name :HDOJ_1241.cpp 8 ************************************************/ 9 10

uva 11853 Paintball dfs找连通块

题意: 给出一个矩形湖, 湖里面有一些圆形地小岛, 问能否从左岸乘船到达右岸,如果能,找出最上面的起点和终点. 题解: 如果能从左岸到达右岸,那么一定不能存在一个连通的岛屿从上岸连到下岸, 所以直接从上到下做dfs,判断是否存在从上岸到下岸地连通块,完成判断.那么接下来就是如何找出最上方地点了,画画图便发现,对于起点,如果存在跨越上岸和左岸地连通岛屿,那么起点一定只能在左岸地交点下方,所以,只需在dfs的过程中更新起点和终点位置即可. 代码: #include <queue> #include

UVa 1103 (利用连通块来判断字符) Ancient Messages

本题就是灵活运用DFS来求连通块来求解的. 题意: 给出一幅黑白图像,每行相邻的四个点压缩成一个十六进制的字符.然后还有题中图示的6中古老的字符,按字母表顺序输出这些字符的标号. 分析: 首先图像是被压缩过的,所以我们要把它解码成一个01矩阵.而且我们还要在原图像的四周加一圈白边,这样图中的白色背景都连通起来了. 黑色连通块的个数就是字符的个数. 观察题中字符样式可知,每种字符中包裹的“白洞”的个数是不同的,所以我们可以根据每个字符中的“白洞”的个数来区别这些字符. 然后我们给所有的连通块染色,