【codevs1002】搭桥

72 篇文章 0 订阅
55 篇文章 0 订阅

题目描述 Description

有一矩形区域的城市中建筑了若干建筑物,如果某两个单元格有一个点相联系,则它们属于同一座建筑物。现在想在这些建筑物之间搭建一些桥梁,其中桥梁只能沿着矩形的方格的边沿搭建,如下图城市1有5栋建筑物,可以搭建4座桥将建筑物联系起来。城市2有两座建筑物,但不能搭建桥梁将它们连接。城市3只有一座建筑物,城市4有3座建筑物,可以搭建一座桥梁联系两栋建筑物,但不能与第三座建筑物联系在一起。

输入描述 Input Description

在输入的数据中的第一行包含描述城市的两个整数r 和c, 分别代表从北到南、从东到西的城市大小(1 <= <= 50 and 1 <=  c <= 50). 接下来的r 行, 每一行由个(“#”)和(“.”)组成的字符. 每一个字符表示一个单元格。“#”表示建筑物,“.”表示空地。

 

输出描述 Output Description

在输出的数据中有两行,第一行表示建筑物的数目。第二行输出桥的数目和所有桥的总长度。

样例输入 Sample Input

样例1

3 5

#...#

..#..

#...#

 

样例2

3 5

##...

.....

....#

 

样例3

3 5

#.###

#.#.#

###.#

 

样例4:

3 5

#.#..

.....

....#

 

样例输出 Sample Output

样例1

5

4 4

 

样例2

2

0 0

 

样例3

1

0 0

 

样例4

3

1 1

【题解】

dfs+kruskal 不要妄想读懂我的代码

【代码】

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int sx[8]={1,1,1,0,0,-1,-1,-1};
int sy[8]={1,0,-1,1,-1,1,0,-1};
int n,m,tot,num,u,v,p,q,side,sum,sidesum;
char s[100];
int a[100][100],f[2505][2505],fa[3000];
struct hp{
	int x,y,z;
}b[1000000];
bool pd;
inline void dfs(int s,int t){
	for (int i=0;i<8;++i){
		int x=s+sx[i],y=t+sy[i];
		if (x>0&&x<=n&&y>0&&y<=m&&a[x][y]==-1){
			a[x][y]=tot;
			dfs(x,y);
		}
	}
}
int cmp(hp a,hp b){
	return a.z<b.z;
}
int find(int x){
	if (x==fa[x]) return x;
	fa[x]=find(fa[x]);
	return fa[x];
}
int merge(int x,int y){
	int f1=find(x);
	int f2=find(y);
	fa[f1]=f2;
}
int main(){
	scanf("%d%d\n",&n,&m);
	for (int i=1;i<=n;++i){
		gets(s);
		for (int j=1;j<=m;++j)
		  if (s[j-1]=='#') a[i][j]=-1;
	}
	for (int i=1;i<=n;++i)
	  for (int j=1;j<=m;++j)
	    if (a[i][j]==-1){
	    	tot++; a[i][j]=tot;
	    	dfs(i,j);
	    }
	printf("%d\n",tot);
	if (tot==1){
		printf("0 0\n"); return 0;
	}
/*	for (int i=1;i<=n;++i){
		for (int j=1;j<=m;++j)
		  printf("%d",a[i][j]);
		printf("\n");
	}*/
	memset(f,127/3,sizeof(f));
	for (int i=1;i<=n;++i)
	  for (int j=1;j<=m;++j)
	    for (int k=1;k<=n;++k)
	      for (int l=1;l<=m;++l){
	      	u=abs(i-k); v=abs(j-l);
	      	if (a[i][j]!=0&&a[k][l]!=0&&a[i][j]!=a[k][l]&&(u<=1||v<=1)){
	      		if (u<=1) f[a[i][j]][a[k][l]]=min(f[a[i][j]][a[k][l]],v-1);
	      		else if (v<=1) f[a[i][j]][a[k][l]]=min(f[a[i][j]][a[k][l]],u-1);
	      		f[a[k][l]][a[i][j]]=f[a[i][j]][a[k][l]];
	      	}
	      }
//	for (int i=1;i<=tot;++i)
//	  for (int j=1;j<=tot;++j)
//	    if (f[i][j]==0) f[i][j]=707406378;
/*	for (int i=1;i<=tot;++i){
		for (int j=1;j<=tot;++j)
		  printf("%d ",f[i][j]);
		printf("\n");
	}*/
	num=tot-1;
	for (int i=1;i<=tot;++i){
		pd=false;
		for (int j=1;j<=tot;++j)
		  if (f[i][j]!=707406378){
		  	pd=true; break;
		  } 
		if (pd==false) num--;
	}
	num=max(num,0);
	if (num==0){
		printf("0 0"); return 0;
	}
	printf("%d ",num);
	for (int i=1;i<tot;++i)
	  for (int j=i+1;j<=tot;++j)
	    if (i!=j&&f[i][j]!=707406378){
	    	side++;
	    	b[side].x=i; b[side].y=j; b[side].z=f[i][j];
	    }
//	for (int i=1;i<=side;++i)
//	  printf("%d %d %d\n",b[i].x,b[i].y,b[i].z);
	sort(b+1,b+side+1,cmp);
	for (int i=1;i<=tot;++i) fa[i]=i;
	for (int i=1;i<=side;++i){
		if (find(b[i].x)!=find(b[i].y)){
			merge(b[i].x,b[i].y);
			sum++; sidesum+=b[i].z;
			if (num==sum){
				printf("%d\n",sidesum);
				return 0;
			}
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值