签到,今天是连续OJ系列的12天。
Crossword Answers, ACM/ICPC World Finals 1994,又是一道决赛题,在没有经过任何查找网上的代码的情况下,自己写出了这两道决赛题(OJ系列第11天),并且AC,还是小有成就感的。
题目
输入一个r行c列( 1≤r, c≤10) 的网格, 黑格用“*”表示, 每个白格都填有一个字母。 如果一个白格的左边相邻位置或者上边相邻位置没有白格( 可能是黑格, 也可能出了网格边界) , 则称这个白格是一个起始格。首先把所有起始格按照从上到下、 从左到右的顺序编号为1, 2, 3,…, 如图所示
接下来要找出所有横向单词( Across) 。 这些单词必须从一个起始格开始, 向右延伸到一个黑格的左边或者整个网格的最右列。 最后找出所有竖向单词( Down) 。 这些单词必须从一个起始格开始, 向下延伸到一个黑格的上边或者整个网格的最下行。
样例输入
2 2
AT
*O
6 7
AIM*DEN
*ME*ONE
UPON*TO
SO*ERIN
*SA*OR*
IES*DEA
0
意思就是输入0结束程序
样例输出
puzzle #1:
Across
1.AT
3.O
Down
1.A
2.TO
puzzle #2:
Across
1.AIM
4.DEN
7.ME
8.ONE
9.UPON
11.TO
12.SO
13.ERIN
15.SA
17.OR
18.IES
19.DEA
Down
1.A
2.IMPOSE
3.MEO
4.DO
5.ENTIRE
6.NEON
9.US
10.NE
14.ROD
16.AS
18.I
20.A
可以看出,每个样例之间有个换行,然后输出的数字有3个宽度。
代码
import java.util.Scanner;
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner=new Scanner(System.in);
int r;
int c;
int kase=0;
while(true){
r=scanner.nextInt();
if(r==0){//如果是0则程序退出
return;
}
if(kase!=0){//控制输出换行,第一个样例不输出换行
System.out.println();
}
c=scanner.nextInt();
int count=1;//记录字母对应的数字
char [][]matrix=new char[r][c];
int [][]num=new int[r][c];//字母对应的数字数组
for(int i=0;i<r;i++){
String str=scanner.next();
for(int j=0;j<c;j++){
matrix[i][j]=str.charAt(j);
}
}
for(int i=0;i<r;i++){//遍历找起始格,并且将 数字记录在数字数组
for(int j=0;j<c;j++){
if((matrix[i][j]!='*')&&(i==0||j==0||(matrix[i-1][j]=='*'||matrix[i][j-1]=='*'))){
num[i][j]= count;
count++;
}
}
}
for(int i=0;i<r;i++){//遍历找黑格,并在数字数组做好标记,之所以不在上一个循环中做,会影响找起始格
for(int j=0;j<c;j++){
if(matrix[i][j]=='*'){
num[i][j]=-1;
}
}
}
//得到Across单词
System.out.printf("puzzle #%d:\n",(++kase));
System.out.println("Across");
for(int i=0;i<r;i++){
String s="";
int cout=0;//用于找到最开始的起始格
for(int j=0;j<c;j++){
if(num[i][j]!=-1){//如果不是黑格子
s+=matrix[i][j];//将单个字母拼接在一起
cout++;
}else{//遇到黑格子
if(s!=""){
System.out.printf("%3d%s\n",num[i][j-cout],"."+s);//格式化输出
}
s="";//置空,以便下次记录
cout=0;
}
if(j==c-1&&(s!="")){//到一行的末尾,并且当前的单词不为空,就输出该单词
System.out.printf("%3d%s\n",num[i][j-cout+1],"."+s);
}
}
}
//得到Down单词,不过先存到一个字符串数组中,方便根据序号从小到大输出
//与找Across单词不同的是:一列一列的读,找到Down单词,连同最初的起始格的数字储存起来,其他原理同找Across
String []ch=new String[count];
for(int j=0;j<c;j++){//列
String s1="";
int cout1=0;
for(int i=0;i<r;i++){//行
if(num[i][j]!=-1){
s1+=matrix[i][j];
cout1++;
}else{
if(s1!=""){
ch[num[i-cout1][j]]=s1;
}
s1="";
cout1=0;
}
if(i==r-1&&(s1!="")){
ch[num[i-cout1+1][j]]=s1;
}
}
}
//输出所有的Down单词,过滤掉没有储存的
System.out.println("Down");
for(int i=0;i<ch.length;i++){
if(ch[i]!=null){
System.out.printf("%3d%s\n",i,"."+ch[i]);
}
}
}
}
}
意料之中又报了演示错误,不过这次的原因很清楚,就是最后多输出一行,结果还报演示错误,仔细看了看,原来宽度是3个,我看成了2个,改掉,成功AC,此次还不算煎熬的就解决了。