問題提出:
在一個矩形方格中,隨機地塗表格,求所塗多邊形的周長。
我們如果去求圖中所有黑點所組成的多邊形的周長呢?小學我們就學過切割法。對於凸邊形來說,其周長可以等價於一個大矩形的周長。如下圖所示
====》
即周長爲4*5=20
但對於凹多邊形來說,這就不對了,對於這個凹字就可以看出2*(4+5)!=18。那麼應該怎麼求呢?對於普通程序員來說,最熟悉的是遍歷了,但我可以說的是,有更簡單的方法。
我們來分析下,每個小方塊矩形有4條邊,但相鄰的方塊會有重複的邊。如果我們把重複的邊減掉,不就可以得到其周長了嗎。先舉個例子。對於兩個小方塊來說,重合的邊爲2,故其周長爲2*4-2=2*(1+2)=6。其實認真想想也很容易想明白的。好了,那我們怎麼求重合的邊數呢?如果我們把每個小方塊黑點當成一個個的點,然後相鄰的黑點連成線,那就是我們所說的圖了。所重合的邊數,就是這個圖邊數的兩倍,即2e(e爲此圖邊的個數)
根據圖論的知識,所有點的度之和爲邊數的2倍,。設黑點數爲n,則周長爲。我們來上圖中的周長:4*12-(1+3+2+3+4+3+2+2+4+3+2+1)=48-30=18。
以上方法所計算的結果是包含內點的,如第一幅圖中右下角有一個內點,即白點周邊全是黑的。如果不想包括內點,那麼可以先進行對內點處理,全變成黑點,然後再處理。對於第一幅圖,如果計算內點的話,即:4*25-(1+2+3+2+2+1+3+2+2+1+1+1+3+3+1+2+3+2+2+3+2+1+1+2+2)=100-48=52。而根據切割法原理,我們可以得到周長爲2*(2+4)+2(3+4)-2+2(3+4)+2(4+2)+2=12+14+14+12=52。
代碼爲:
int perimeter(int **d,int n)
{
// Print(d,n);
int director[4][2]={{1,0},{0,-1},{-1,0},{0,1}};//方位,右-上-左-下
///////////////////////預處理/////////////////////////////////
//將內點賦1
bool isOne=true;
for(int i=1;i<n-1;i++){
for(int j=1;j<n-1;j++){
if(d[i][j]==0){
isOne=true;
for(int k=0;k<4;k++){
if(d[i+director[k][0]][j+director[k][1]]!=1){//如果有一個方位不爲1,則此點不符合條件
isOne=false;
break;
}
}
if(isOne)
d[i][j]=1;
}
}
}
int Onecount=0,
degree=0;
for(int i=1;i<n-1;i++){
for(int j=1;j<n-1;j++){
if(d[i][j]==1){
Onecount++;//記錄值爲1的點數
for(int k=0;k<4;k++){
if(d[i+director[k][0]][j+director[k][1]]==1)//記錄四個方位值爲1的點數
degree++;
}
}
}
}
return 4*Onecount-degree;//返回周長
}