描述:
曉萌有一個N×N的的棋盤,中間有N*N個正方形的1×1的格子,他隨機在棋盤上撒上一些棋子(假設全部正好落在各個格子里)。他希望知道,當前的棋盤上有多少個不包含棋子的,由至少四個1×1的格子組成的正方形(正方形之間可以有重疊的部分)。
輸入第1行為棋盤的邊長N,第2行-第N+1組成一個每行有N個數字的棋盤,其中數字0表示這個格子內有棋子,1表示這個格子內沒有棋子。(2≤N≤250)
輸出包括多行,每行包括兩個用空格分隔的數字,分別表示可以找到的正方形的邊長和這種邊長的正方形的個數。
樣例輸入
6
101111
001111
111111
001111
101101
111001
樣例輸出
2 10 //2*2的正方形有10個
3 4 //3*3的正方形有4個
4 1 //4*4的正方形有1個
分析:
顯然這是個動態規划,若用暴力搜索,會在大數組上超時,所以需要每次保存上次的狀態
先來分析下2*2的正方形,如下圖:
從上圖可以看出,當在第s[i][j]數組上,且這個數組值為1(有棋子),那它會與之前地s[i-1][j-1]、s[i-1][j]、s[i][j-1]有關,若這3個任意一個都不滿足(為0)的話,那么s[i][j]就只能是個1*1正方形
再來深入分析,3*3的正方形,如下圖:
從上圖可以看出,要想第s[i][j]數組上構成一個大於等於3*3的正方形,必須s[i-1][j-1]、s[i-1][j]、s[i][j-1]都至少是個2*2的正方形,比如上圖(3,3), 不然就會像上圖(2,2)那樣
從這里我們可以看出s[i][j]非0情況下, 會等於 這3個數組(s[i-1][j-1]、s[i-1][j]、s[i][j-1])的最小值+1
最后再分析一個有0數組,就迎刃而解了:
同樣地對於一個n*n正方形(n>=2),必定滿足(n-1)*(n-1)正方形、(n-2)*(n-2)正方形 ... ...
代碼如下:
#include<stdio.h>
int s[300][300]={0},tp[300]={0}; int main() { int i,j,n,min=0,m=1,cnt; scanf("%d",&n); for(i=1;i<=n;i++) for(j=1;j<=n;j++) scanf("%1d",&s[i][j]); for(i=1;i<=n;i++) for(j=1;j<=n;j++) { if(s[i][j]!=0) //第s[i][j]數組上,且這個數組值為1(有棋子)
{ min=(s[i-1][j]>s[i-1][j-1])?s[i-1][j-1]:s[i-1][j]; min=(s[i][j-1]>min)?min:s[i][j-1]; s[i][j]=min+1; //等於 這3個數組(s[i-1][j-1]、s[i-1][j]、s[i][j-1])的最小值+1
for(cnt=2;cnt<=min+1;cnt++) //對於一個n*n正方形(n>=2),必定滿足(n-1)*(n-1)正方形、(n-2)*(n-2)正方形 ... ...
tp[cnt]++; } } for(i=2;i<=n;i++) if(tp[i]!=0) { if(m) { printf("%d %d",i,tp[i]); m=0; } else printf("\n%d %d",i,tp[i]); } return 0; }