- 题目大意
给你一个r * c的格子,每个格子有一个 ‘ ’ 或者 ‘/’ 的墙,以及打掉墙的费用,问使得所有块联通的最小费用。(自己可以配合图来看好理解一点)
- 解题思路
我们可以将其转化成联通块的问题,就是把每个格子看成两部分,左侧和右侧。以一行来看,假设两个格子A,B。那么B格子的右侧的编号一定和A格子的左侧的编号相同。给每个格子的左右侧标上号,然后加入边,边的两个端点为一个格子的两个编号。权值为墙的费用然后处理行与行之间的边,然后假设上边格子为A,下面格子为B。那么如果A是‘/’,B是’/’,那么A的右格子和B的左格子是相通的,这时候加一条边,将权值设为0就可以了。(注意位置和数组大小!!!)
- 代码
#include<algorithm> #include<cstdio> #include<cmath> #include<cstring> #include<iostream> #include<string> using namespace std; const int MAX = 1e6; int fa[MAX]; string str[400]; int num[150][150]; int sum,sum1,cnt; void init() { for (int i = 1; i <= MAX; i++) { fa[i] = i; } cnt=0; } struct Edge { int u, v, w; bool operator<(const Edge &rhs)const { return w < rhs.w; } }e[MAX]; struct Edge2{ int u,v; }maps[150][150]; void addEdge(int u,int v,int w) { e[cnt].v=v; e[cnt].u=u; e[cnt++].w=w; } int find(int x) { if (x == fa[x]) return x; else return fa[x] = find(fa[x]); } bool Union(int x, int y) { int fx = find(x), fy = find(y); if (fx == fy) return false; fa[fx] = fy; return true; } void kruskal(int m) { sort(e, e + m); for (int i = 0; i < m; i++) { int u = e[i].u, v = e[i].v, w = e[i].w; if (Union(u, v)) { sum +=w; } } } int main() { int t,n, m; scanf("%d",&t); for(int q=1;q<=t;q++) { scanf("%d%d",&n,&m); init(); for(int i=0;i<n;i++) { cin>>str[i]; } for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { scanf("%d",&num[i][j]); } } int p = 1; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (j == 0) { maps[i][j].u = p++; maps[i][j].v = p++; addEdge(maps[i][j].u, maps[i][j].v, num[i][j]); } else { maps[i][j].u = maps[i][j - 1].v; maps[i][j].v = p++; addEdge(maps[i][j].u, maps[i][j].v, num[i][j]); } if (i != 0) { if (str[i - 1][j] == '/') { if (str[i][j] == '/') { addEdge(maps[i][j].u, maps[i - 1][j].v, 0); } else { addEdge(maps[i][j].v, maps[i - 1][j].v, 0); } } else { if (str[i][j] == '/') { addEdge(maps[i][j].u, maps[i - 1][j].u, 0); } else { addEdge(maps[i][j].v, maps[i - 1][j].u, 0); } } } } } sum=0; kruskal(cnt); printf("Case %d: %d ",q,sum); } return 0; }