回溯演算法的應用:C語言中的堡壘問題(不要把換行符輸到數組裡QAQ)
阿新 • • 發佈:2019-01-28
描述
城堡是一個4×4的方格,為了保衛城堡,現需要在某些格子裡修建一些堡壘。城堡中的某些格子是牆,其餘格子都是空格,堡壘只能建在空格里,每個堡壘都可以向上下左右四個方向射擊,如果兩個堡壘在同一行或同一列,且中間沒有牆相隔,則兩個堡壘都會把對方打掉。問對於給定的一種狀態,最多能夠修建幾個堡壘。
輸入
每個測例以一個整數n(1<=n<=4)開始,表示城堡的大小。接下來是n行字元每行n個,‘X’表示該位置是牆,‘.’表示該位置是空格。n等於0標誌輸入結束。
輸出
每個測例在單獨的一行輸出一個整數:最多修建堡壘的個數。
輸入樣例
4
.X..
….
XX..
….
2
XX
.X
3
.X.
X.X
.X.
3
…
.XX
.XX
4
….
….
….
….
0
輸出樣例
5
1
5
2
4
這道題的輸入很奇怪!!!很容易錯!!!
如果用兩個for迴圈和scanf一個個輸入字元,會把換行符輸入進去。
用一個for迴圈和gets一行一行輸入,也會把第一個n後面的換行符輸入進去。
所以還要在前面加一個getchar把第一個換行符存到temp變數中。
總之很坑QAQ
#include<stdio.h>
int output[100]={0};//儲存結果的陣列
int n;
int cnt=0;//用來記錄輸入了幾組資料,方便存出結果和輸出。
char cb[5][5];//城堡地圖
int bl[5][5];//放堡壘的地圖
//兩個地圖是重合的
void testout()//檢查建了多少個堡壘,記錄最大堡壘數。
{
int sum=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(bl[i][j]==1) sum++; //一共建了多少堡壘
}
}
if(sum>output[cnt]) output[cnt]=sum;//把最大堡壘數存在陣列output中
}
int check(int m)//檢查此處是否能建堡壘
{
int x=m/n;
int y=m%n;
if(bl[x][y]==0) return 1 ;//沒有堡壘是一定符合要求的。直接返回1。
if(cb[x][y]=='X'&&bl[x][y]==1) return 0;//有牆的地方不能建堡壘
int flag1=1,flag2=1;
for(int j=0;j<y;j++)
{
if(bl[x][j]==1)
{
flag1=0;
for(int i=j+1;i<y;i++)
{
if(cb[x][i]=='X') flag1=1;
}
}
}
for(int j=0;j<x;j++)
{
if(bl[j][y]==1)
{
flag2=0;
for(int i=j+1;i<x;i++)
{
if(cb[i][y]=='X') flag2=1;
}
}
}
//新建的堡壘必須和同一行或同一列的其他堡壘間相隔一堵牆
if(flag1==1&&flag2==1)
{
return 1;
}
else return 0;
}
void chengbao(int m)
{
if(m==n*n)
{
testout();
}
int x=m/n;
int y=m%n;//將一維數字轉換為二維陣列的座標 (從0開始)
if(m<n*n)
{
for(int i=1;i>=0;i--)
{
bl[x][y]=i;
if(check(m)==0) continue;//不符合要求則繼續取值或回溯至符合要求
else chengbao(m+1); //符合要求則繼續遞迴呼叫
}
}
}
void print()//輸出
{
for(int i=1;i<=cnt;i++)
{
printf("%d\n",output[i]);
}
}
int main()
{
while(1)//輸入資料
{
scanf("%d",&n);
if(n==0) break;
cnt++;
char temp=getchar();//把n後面的換行符存進去,否則會存入cb陣列
for(int i=0;i<=n-1;i++)
{
gets(cb[i]);
}
chengbao(0);//每輸入完一組資料,進行一次運算
}
print();//輸出結果
}