UVa 232, Crossword Answers

Problem

传送门

Mean1

输入一个r行c列(1≤r, c≤10)的网格,黑格用“*”表示,每个白格都填有一个字母。如果一个白格的左边相邻位置或者上边相邻位置没有白格(可能是黑格,也可能出了网格边界),则称这个白格是一个起始格。
首先把所有起始格按照从上到下、从左到右的顺序编号为1,2,3,…。
接下来要找出所有横向单词(Across)。这些单词必须从一个起始格开始,向右延伸到一个黑格的左边或者整个网格的最右列。最后找出所有竖向单词(Down)。这些单词必须从一个起始格开始,向下延伸到一个黑格的上边或者整个网格的最下行。

Analysis

首先搜索起始格并依次打标记。以数组a,b记录横纵坐标信息,数组u,w记录横向起始格序列与纵向起始格序列。
处理横向单词时依次访问u数组记录未访问过的点(其横纵坐标已由a,b数组记录),并把已访问过的点标记以避免重复访问。
纵向单词亦然。由于此前为避免重复访问已对u数组进行过修改,所以特意使用w数组。

Code

#include<stdio.h>
#include<cstring>
char map[15][15];
int a[105],b[105],u[15][15],w[15][15];
int r,c,cnt,t=0;
void de(int x,int y){
    if(map[x][y]!='*' && (x==0 || y==0 || map[x-1][y]=='*' || map[x][y-1]=='*')){
        u[a[++cnt]=x][y]=1;w[x][b[cnt]=y]=1;
    }
}
int main(){
    while(~scanf("%d",&r) && r){
        memset(map,0,sizeof(map));
        if(t) printf("\n");
        scanf("%d",&c);
        for(int i=0;i<r;i++) scanf("%s",map[i]);
        cnt=0;
        for(int i=0;i<r;i++)
          for(int j=0;j<c;j++) de(i,j);
        printf("puzzle #%d:\nAcross\n",++t);
        for(int i=1;i<=cnt;i++) if(u[a[i]][b[i]]){
            int x=a[i],y=b[i];
            printf("%3d.",i);
            for(;;){
                u[x][y]=0;
                putchar(map[x][y]);
                if(++y>=c || map[x][y]=='*'){printf("\n");break;}
            }
        }
        printf("Down\n");
        for(int i=1;i<=cnt;i++) if(w[a[i]][b[i]]){
            int x=a[i],y=b[i];
            printf("%3d.",i);
            for(;;){
                w[x][y]=0;
                putchar(map[x][y]);
                if(++x>=r || map[x][y]=='*'){printf("\n");break;}
            }
        }
    }
    return 0;
}

  1. 来自刘汝佳《算法竞赛入门经典(第2版)》
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值