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