1. 程式人生 > 實用技巧 >題解 P6369 [COCI2006-2007#6] MARATON

題解 P6369 [COCI2006-2007#6] MARATON

蒟蒻題解首祭!!!

咕了三星期了

先分析下題意:
一個由各個字母與 ‘.’ 組成的正方形矩陣(邊長小於等於30)

求任意行列斜線上有沒有3個連續相同的字母。

就這,無了。

思考下演算法

資料範圍很小(只有30),我們為什麼不用最無腦的遍歷列舉呢?

輸入就不用多說了,一個字元型陣列,但要注意宣告時,冗餘要稍多一些,防止訪問越界。

for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
		cin>>MAP[i][j];

遍歷判斷:
某玩家若勝利則此玩家字母連線必定為以下四情況之一

設遍歷到的這個位置座標為(x,y)

類 型 座標1 座標2 座標3
(x-1,y) (x,y) (x+1,y)
(x,y+1) (x,y) (x,y-1)
斜線 (x-1,y+1) (x,y) (x+1,y-1)
斜線 (x+1,y-1) (x,y) (x-1,y+1)

判斷函式:

void JUDGE(int x,int y)
{
	if((MAP[x-1][y]==MAP[x][y])&&(MAP[x+1][y]==MAP[x][y]))
		OUT(MAP[x][y]);
	if((MAP[x][y-1]==MAP[x][y])&&(MAP[x][y+1]==MAP[x][y]))
		OUT(MAP[x][y]);
	if((MAP[x-1][y-1]==MAP[x][y])&&(MAP[x+1][y+1]==MAP[x][y]))
		OUT(MAP[x][y]);
	if((MAP[x+1][y-1]==MAP[x][y])&&(MAP[x-1][y+1]==MAP[x][y]))
		OUT(MAP[x][y]);
}

這個時候陣列冗餘就發揮作用了,可以略去越界判斷只需要輸出時進行一次特判就可以。

輸出函式:

void OUT(char c)
{
	if(c!='.'&&c!=0)
	{	
		printf("%c",c);
		sign=false;
	}
}

此外,我們還需要一個sign變數(bool)記錄是否有贏家,以此判斷是否輸出"ongoing"

if(sign)
	printf("ongoing");

完整程式碼(20ms,660.00KB):

#include<bits/stdc++.h>
using namespace std;

int n;
char MAP[35][35];
bool sign=true;//記錄是否有贏家
void JUDGE(int,int),OUT(char);

int main()
{
	memset(MAP,0,sizeof(MAP));
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			cin>>MAP[i][j];
	for(int i=1;i<=n&&sign;i++)//迴圈必須判斷sign情況 不然可能重複輸出
		for(int j=1;j<=n&&sign;j++)
			JUDGE(i,j);
	if(sign)//若遍歷後無贏家輸出"ongoing"
		printf("ongoing");
	return 0;
}

void JUDGE(int x,int y)
{
	if((MAP[x-1][y]==MAP[x][y])&&(MAP[x+1][y]==MAP[x][y])) 
		OUT(MAP[x][y]);//行
	if((MAP[x][y-1]==MAP[x][y])&&(MAP[x][y+1]==MAP[x][y]))
		OUT(MAP[x][y]);//列
	if((MAP[x-1][y-1]==MAP[x][y])&&(MAP[x+1][y+1]==MAP[x][y]))
		OUT(MAP[x][y]);//斜線
	if((MAP[x+1][y-1]==MAP[x][y])&&(MAP[x-1][y+1]==MAP[x][y]))
		OUT(MAP[x][y]);//斜線
}

void OUT(char c)
{
	if(c!='.')//棋盤中可能有連續3個'.'構成的線
	{	
		printf("%c",c);
		sign=false;//更新sign
	}
}

完結撒fa~