UVALive-7303 Aquarium (最小生成树)

题目大意:在nxm的方格中,每一个1x1的小方格中都有一堵沿对角线的墙,并且每堵墙都有一个坚固程度,这些墙将nxm的方格分割成了若干个区域。现在要拆除一些墙,使其变成一个区域。

题目分析:将区域视作点,将墙视作边,这样问题就变成了求最小生成树。

代码如下:

# include<iostream>
# include<cstdio>
# include<cmath>
# include<vector>
# include<list>
# include<queue>
# include<cstring>
# include<algorithm>
using namespace std;
# define LL long long

const int INF=1000000000;
const int N=1000;
const double eps=1e-10;
const double inf=1e20;

int n,m;
char p[105][105];
int a[105][105];
int vis[105][105][2];

struct Edge
{
	int fr,to,w;
	bool operator < (const Edge &a) const{
		return w<a.w;
	}
};
Edge e[20000];
int fa[20000];

bool ok(int x,int y)
{
	return x>=0&&x<n&&y>=0&&y<m;
}

void dfs(int x,int y,int f,int cnt)
{
	vis[x][y][f]=cnt;
	if(p[x][y]==‘\\‘){
		if(f==1){
			if(ok(x,y-1)){
				if(p[x][y-1]==‘\\‘&&vis[x][y-1][0]==-1) dfs(x,y-1,0,cnt);
				if(p[x][y-1]==‘/‘&&vis[x][y-1][1]==-1) dfs(x,y-1,1,cnt);
			}
			if(ok(x+1,y)&&vis[x+1][y][0]==-1)
				dfs(x+1,y,0,cnt);
		}else{
			if(ok(x-1,y)&&vis[x-1][y][1]==-1)
				dfs(x-1,y,1,cnt);
			if(ok(x,y+1)){
				if(p[x][y+1]==‘\\‘&&vis[x][y+1][1]==-1) dfs(x,y+1,1,cnt);
				if(p[x][y+1]==‘/‘&&vis[x][y+1][0]==-1) dfs(x,y+1,0,cnt);
			}
		}
	}else{
		if(f==1){
			if(ok(x,y+1)){
				if(p[x][y+1]==‘\\‘&&vis[x][y+1][1]==-1) dfs(x,y+1,1,cnt);
				if(p[x][y+1]==‘/‘&&vis[x][y+1][0]==-1) dfs(x,y+1,0,cnt);
			}
			if(ok(x+1,y)&&vis[x+1][y][0]==-1)
				dfs(x+1,y,0,cnt);
		}else{
			if(ok(x-1,y)&&vis[x-1][y][1]==-1)
				dfs(x-1,y,1,cnt);
			if(ok(x,y-1)){
				if(p[x][y-1]==‘\\‘&&vis[x][y-1][0]==-1) dfs(x,y-1,0,cnt);
				if(p[x][y-1]==‘/‘&&vis[x][y-1][1]==-1) dfs(x,y-1,1,cnt);
			}
		}
	}
}

int find_fa(int x)
{
	int u=x;
	while(fa[u]!=u)
		u=fa[u];
	while(fa[x]!=u){
		int t=x;
		x=fa[x];
		fa[t]=u;
	}
	return u;
}

int main()
{
	int T;
	scanf("%d",&T);
	int cas=0;
	while(T--)
	{
		scanf("%d%d",&n,&m);
		memset(vis,-1,sizeof(vis));
		for(int i=0;i<n;++i)
			scanf("%s",p[i]);
		for(int i=0;i<n;++i)
			for(int j=0;j<m;++j)
				scanf("%d",&a[i][j]);
		int cnt=0;
		for(int i=0;i<n;++i){
			for(int j=0;j<m;++j){
				if(vis[i][j][0]==-1){
					dfs(i,j,0,cnt);
					++cnt;
				}
				if(vis[i][j][1]==-1){
					dfs(i,j,1,cnt);
					++cnt;
				}
			}
		}
		int k=0;
		for(int i=0;i<n;++i){
			for(int j=0;j<m;++j){
				if(vis[i][j][0]==vis[i][j][1]) continue;
				e[k].fr=vis[i][j][0];
				e[k].to=vis[i][j][1];
				e[k].w=a[i][j];
				++k;
			}
		}
		sort(e,e+k);
		for(int i=0;i<cnt;++i)
			fa[i]=i;
		int ans=0;
		for(int i=0;i<k;++i){
			int f1=find_fa(e[i].fr);
			int f2=find_fa(e[i].to);
			if(f1!=f2){
				ans+=e[i].w;
				fa[f1]=f2;
			}
		}
		printf("Case %d: %d\n",++cas,ans);
	}
	return 0;
}

  

时间: 2024-10-12 16:07:40

UVALive-7303 Aquarium (最小生成树)的相关文章

H - Aquarium (UVALive - 7303 )

- 题目大意 给你一个r * c的格子,每个格子有一个 ' \ ' 或者 '/' 的墙,以及打掉墙的费用,问使得所有块联通的最小费用.(自己可以配合图来看好理解一点) - 解题思路 我们可以将其转化成联通块的问题,就是把每个格子看成两部分,左侧和右侧.以一行来看,假设两个格子A,B.那么B格子的右侧的编号一定和A格子的左侧的编号相同.给每个格子的左右侧标上号,然后加入边,边的两个端点为一个格子的两个编号.权值为墙的费用然后处理行与行之间的边,然后假设上边格子为A,下面格子为B.那么如果A是'/'

UVAlive 6622 Absurdistan Roads(最小生成树+LCA)

题目地址:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4633 思路:每个点之间连边,权值为两点之间的最短距离.则该图的最小生成树的n-1条边在最终的n条边内.则两点(i,j)之间距离为dist[i]+dist[j]-2*dist[ LCA(i,j) ](dist[i]表示根节点(设为1)到i节点的距离).若树上每点之间的

UVALive 3662 Another Minimum Spanning Tree 曼哈顿最小生成树

题目链接:点击打开链接 题意: 给定二维平面的n个点坐标,问曼哈顿MST 的值. 模版题 #include <stdio.h> #include <iostream> #include <algorithm> #include <sstream> #include <stdlib.h> #include <string.h> #include <limits.h> #include <vector> #incl

uvaLive7303 Aquarium (最小生成树)

题意:给R*C的房间,每个房间被左上-右下或右上-左下的墙分割为两个小房间,将分割移除有一定花费,问使所有小房间联通需要的最小花费 把每个房间分成左右(上下?)两个点,判一判,本来就联通的加零边,一个房间里的两个点间加花费的边,跑Kruskal即可 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 5 using namespace std; 6 const int maxN=110; 7 8

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

UVALive - 7303- Aquarium 题目链接:7303 题目大意:给你一个r * c的格子,每个格子有一个 ' \ ' 或者 '/' 的墙,以及打掉墙的费用,问使得所有块联通的最小费用.(看图好理解) 题目思路:就是将他化成一个图,联通的块相当于一个点,两个点之间有一条边,边的权值为墙的费用. 转化为连通块的思路是:每个格子看成两部分,左侧和右侧.以一行来看,假设两个格子A,B.那么B格子的右侧的编号一定和A格子的左侧的编号相同.如图所示 给每个格子的左右侧标上号,然后加入边,边的

组队赛第五场 组合隔板法+最小生成树预处理并查集

UVALive 6434 题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4445 这题正好就是大一小学期的时候好像是曦曦出的那个牛那题吧,就是要买多少块板然后正好把牛给拦完.这题也是一样,就是找最大的距离,当做隔板,依次把最大的距离去掉,最后的就是最小的了. #include<iostream> #in

UVALive 5713 Qin Shi Huang&#39;s National Road System秦始皇修路(MST,最小瓶颈路)

题意: 秦始皇要在n个城市之间修路,而徐福声可以用法术位秦始皇免费修1条路,每个城市还有人口数,现要求徐福声所修之路的两城市的人口数之和A尽量大,而使n个城市互通需要修的路长B尽量短,从而使得A/B最大.问A/B最大是多少?(1000个城市) 思路: 老徐可免费修得1条路,那么剩下最多也只需要修n-2条路了,这n-2条路要尽量挑短的,而老徐的那条无所谓长短,只要两城人口尽量多即可.这是没有什么贪心策略的,因为老徐所修之路会影响MST的权值之和的大小.穷举所有城市对要O(n*n),再求次MST需要

次最小生成树 模版

次小生成树(转) 转载(http://www.cnblogs.com/z360/p/6875488.html) 所谓次小生成树,顾名思义就是从生成树中取出的第二小的生成树. 我们在前面已经说过最小生成树的概念及代码实现了,所以接下来要说的次小生成树应该比较简单理解了. 求次小生成树的两种方法 1:首先求出最小生成树T,然后枚举最小生成树上的边,计算除了枚举的当前最小生成树的边以外的所有边形成的最小生成树Ti,然后求最小的Ti就是次小生成树.2:首先计算出最小生成树T,然后对最小生成树上任意不相邻

HDU1863 畅通工程---(最小生成树)

畅通工程 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 27972    Accepted Submission(s): 12279 Problem Description 省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).经过调查评估,得到的统计表中列出