usaco chapter 2.1 castle

 图论问题,计算房间数量,递归访问四周的格子,遇到墙退回,统计格子数,记录访问后的格子,无法递归时退出,找另外一个房间。

 代码:


#include<stdio.h>
#include<string.h>
#define max 100
typedef struct operate
{
 int total;
 char direction;
 int local[2];
}operate;
typedef struct node
{
 int wall[4];
}node;
node map[max][max];
int vis[max][max];
int room[max*max];
int t,l,h;

int dfs(int x,int y)   //x为纵坐标 y为横坐标;
{
 int count=1;
 if(vis[x][y])return 0;
 vis[x][y]=t;
 if(!map[x][y].wall[0]&&x+1<=h)  //南方无墙;
  count+=dfs(x+1,y);
 if(!map[x][y].wall[1]&&y+1<=l)  //东方无墙;
  count+=dfs(x,y+1);
 if(!map[x][y].wall[2]&&x-1>0)  //北方无墙;
  count+=dfs(x-1,y);
 if(!map[x][y].wall[3]&&y-1>0)  //西方无墙;
  count+=dfs(x,y-1);
 return count;
}
void base_2(int num,node* temp)
{
// node temp;
 int i=3;
 while(num!=0)
 {
  temp->wall[i--]=num%2;
  num/=2;
 }
// return temp;
}

operate search(int y,int x)

 int j;
 operate temp;
 temp.total=0;
 if(map[y][x].wall[2]==1&&y-1<=h)      //推倒北墙
 if(vis[y-1][x]!=vis[y][x])
 {
  j=room[vis[y-1][x]]+room[vis[y][x]];
  if(j>temp.total)
  {
   temp.total=j;
   temp.local[0]=y;
   temp.local[1]=x;
   temp.direction='N';
  }
 }
 
 if(map[y][x].wall[1]==1&&x+1<=l)      //推倒东墙
 if(vis[y][x+1]!=vis[y][x])
 {
  j=room[vis[y][x+1]]+room[vis[y][x]];
  if(j>temp.total)
  {
   temp.total=j;
   temp.local[0]=y;
   temp.local[1]=x;
   temp.direction='E';
  }
 }
 return temp;
}
int main()
{
 freopen("castle.out","w",stdout);
 freopen("castle.in","r",stdin);
 int i,j,temp;
// int room[max*max];
 int ans=0;
 operate tp,push;
 scanf("%d%d",&l,&h);
 memset(vis,0,sizeof(vis));
 memset(map,0,sizeof(map));
 for(i=1;i<=h;i++)
 for(j=1;j<=l;j++)
 {
  scanf("%d",&temp);
  base_2(temp,&map[i][j]);
  

 }

 t=1;ans=0;
 for(i=1;i<=h;i++)
 for(j=1;j<=l;j++)
 if(!vis[i][j])
 {
  room[t++]=dfs(i,j);
  ans=ans > room[t-1]? ans : room[t-1];
 }
 
 push.total=0;
 for(i=1;i<=l;i++)
 for(j=h;j>0;j--)
 {
  tp=search(j,i);
  push=push.total>=tp.total? push:tp;
 }

 printf("%d\n",t-1);
 printf("%d\n",ans);
 printf("%d\n",push.total);
 printf("%d %d %c\n",push.local[0],push.local[1],push.direction);
 return 0;
}

 

思路还是很清晰的,但是调试很困难。把各种操作单独写进一个函数分别调用,可以方便调试。

此外题目中最后一个数据的输出很让人纠结,英文原题的要求:

Choose the optimal wall to remove from the set of optimal walls by choosing the module farthest to the west (and then, if still tied, farthest to the south). If still tied, choose 'N' before 'E'. Name that wall by naming the module that borders it on either the west or south, along with a direction of N or E giving the location of the wall with respect to the module.

 

这句话必须要仔细斟酌:

选择最佳的墙推倒,从一些模块(也就是格子)的集合中,选择最大程度(farthest在这里这么理解)靠西的模块,和靠南的模块。推墙时,北边的墙优先于东边的墙。模块的边界在西和南,指向北或东,这样就给出了一堵墙关于该模块的位置。

                                                                    N

第二句很拗口,其实凭感觉就可以理解了,这段话实际是告诉你参考坐标是W     E

                                                                    S

第一句更重要,它告诉你优先级。因为不同的房间会包含很多个格子,所以有很多个边界格子,推倒这些边界格子的墙让2个房间联通都能得到解,但我们必须按优先级,选择正确的格子,和推倒的墙。

 推墙操作只要将格点从西南角向上枚举和向右枚举。先判断推N的后果再判断E,只更新结果大的。

 

 

本文使用Blog_Backup未注册版本导出,请到soft.pt42.com注册。

转载于:https://www.cnblogs.com/eggeek/archive/2011/09/26/2281194.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值