codevs 1002

题目描述 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(并查集当然是要用的)做了;(题意貌似没说要让桥最短?假装题目说了吧)

然后几个小技巧和陷阱:

1、第一问求DFS时直接用ans表示并查集的代表元,所以vis数组就不要开成bool啦~;

2、建桥那一段(就是我写的build函数)需要一些奇怪的技巧,pd函数(判断    不想用check表示函数怪我咯~ 反正我没写panduan已经很不错了QAQ)返回0表示不能建(因为两个点已经联通) 返回1表示可以继续;(这里实在不会,看了下题解)

前方高能,划重点:

3、build函数你可以复制粘贴,但一定要保证进行了修改!!!!!!!我少改了一个地方检查了10分钟!!!!!!!!!!(我输出调试过程,眼睁睁地看着数据出错,却不知道错在哪Orz);

4、斜着的,也是可以连的!我开始没注意,样例也没有这个说明,所以我一开始只定义了上下左右的dfs,所以交上去全部WA;

5、YJQ是非常naive的

(╯‵□′)╯︵┻━┻

附上代码:

//作者WXH
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>


using namespace std;


char a[55][55];
int r,c,ans,cnt,ans2;
int vis[55][55];
int dx[9]={0,1,-1,0,0,1,1,-1,-1};
int dy[9]={0,0,0,1,-1,1,-1,1,-1};
int f[100010];


struct edge
{
int x,y,val;
}e[100010];


bool cmp(edge a,edge b)
{
return a.val<b.val;
}


int findfa(int x)
{
return f[x]==x?x:f[x]=findfa(f[x]);
}


bool pd(int x1,int y1,int x2,int y2,int t)
{
if(x2<1||x2>r||y2<1||y2>c||!vis[x2][y2]) return 1;
if(vis[x2][y2]==vis[x1][y1]) return 0;
e[++cnt].x=vis[x1][y1];
e[cnt].y=vis[x2][y2];
e[cnt].val=t-1;
//printf("[%d %d %d %d %d]\n",x1,y1,x2,y2,t-1);
return 1;
}


void dfs(int x,int y)
{
vis[x][y]=ans;
for(int i=1;i<=8;i++)
{
if(a[x+dx[i]][y+dy[i]]=='#'&&!vis[x+dx[i]][y+dy[i]])
{
vis[x+dx[i]][y+dy[i]]=ans;
dfs(x+dx[i],y+dy[i]);
}
}
}


void build(int x,int y)
{
for(int i=x+1;i<=r;i++)
{
//printf("{%d %d %d %d}下移\n",x,y,i,y);
if(!pd(x,y,i,y,i-x)||!pd(x,y,i,y+1,i-x)||!pd(x,y,i,y-1,i-x)) break;
}
for(int i=x-1;i;i--)
{ //printf("{%d %d %d %d}上移\n",x,y,i,y);
if(!pd(x,y,i,y,x-i)||!pd(x,y,i,y+1,x-i)||!pd(x,y,i,y-1,x-i)) break;
}
for(int i=y+1;i<=c;i++)
{
//printf("{%d %d %d %d}右移\n",x,y,x,i);
if(!pd(x,y,x,i,i-y)||!pd(x,y,x+1,i,i-y)||!pd(x,y,x-1,i,i-y)) break;
}
for(int i=y-1;i;i--)
{
//printf("{%d %d %d %d}左移\n",x,y,x,i);
if(!pd(x,y,x,i,y-i)||!pd(x,y,x+1,i,y-i)||!pd(x,y,x-1,i,y-i)) break;
}
}


int main()
{
scanf("%d%d",&r,&c);
for(int i=1;i<=r;i++)
scanf("%s",a[i]+1);
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
if(a[i][j]=='#'&&!vis[i][j])
ans++,dfs(i,j);
printf("%d\n",ans);
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
if(vis[i][j]) 
{
build(i,j);
//printf("%d<->%d,vis[][]=%d\n",i,j,vis[i][j]);
}
sort(e+1,e+cnt+1,cmp);
for(int i=1;i<=ans;i++) f[i]=i;
ans=0;
for(int i=1;i<=cnt;i++)
{
if(findfa(e[i].x)!=findfa(e[i].y))
{
f[findfa(e[i].x)]=findfa(e[i].y);
ans++;
ans2+=e[i].val;
}
}
printf("%d %d",ans,ans2);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值