给出4*4的网格平面,要求在这个16个格子里面放入楼层分别是1、2、3、4层高的楼栋;
要求每行以及每列的1~4层楼必须且只能出现一次;
给出条件是从每个方向上所能看到的不被遮挡的楼栋数目;
Example:
To understand how the puzzle works, this is an example of a row with 2 clues. Seen from the left side there are 4 buildings visible while seen from the right side only 1:
There is only one way in which the skyscrapers can be placed. From left-to-right all four buildings must be visible and no building may hide behind another building:
Example of a 4 by 4 puzzle with the solution:
代码(我这个是用穷举的方法来做的,先算出4!一共24种组合,然后依次遍历,其实比较笨,应该有更聪明的方法,以后有空了想想):
typedef struct _AssNode{int Valuegroup[4];int LeftViewCnt;int RightViewCnt;
}AssNode;int GetLeftViewCnt(int *Buff, int Sz){int i, j;int Cnt = Sz;if(Sz < 2) return Sz;/*从第二个数开始遍历,如果他前面有数比他大,说明被遮挡,返回值-1*/for(i=1; i<Sz; i++){for(j=0; j<i; j++){if(Buff[j] > Buff[i]){Cnt--;break;}}}return Cnt;
}int GetRightViewCnt(int *Buff, int Sz){int i, j;int Cnt = Sz;if(Sz < 2) return Sz;/*从倒数第二个数开始遍历,如果他后面有数比他大,说明被遮挡,返回值-1*/for(i=Sz-2; i>=0; i--){for(j=Sz-1; j>i; j--){if(Buff[j] > Buff[i]){Cnt--;break;}}}return Cnt;
}int Get4X4Assemble(AssNode *Assemble){int i, j, k, z;int cnt = 0;for(i=1; i<=4; i++){for(j=1; j<=4; j++){if(j == i)continue;for(k=1; k<=4; k++){if(k == i || k == j)continue;for(z=1; z<=4; z++){if(z == i || z == j || z == k)continue;Assemble[cnt].Valuegroup[0] = i;Assemble[cnt].Valuegroup[1] = j;Assemble[cnt].Valuegroup[2] = k;Assemble[cnt].Valuegroup[3] = z;Assemble[cnt].LeftViewCnt = GetLeftViewCnt(Assemble[cnt].Valuegroup, 4);Assemble[cnt].RightViewCnt = GetRightViewCnt(Assemble[cnt].Valuegroup, 4);cnt++;}}}}
}/*判断数组列是否是1'2'3'4的组合*/
int IsColumeOrder(int ** buff){int i, j;int cnt = 0;for(j=0; j<4; j++){cnt = 0;for(i=1; i<=4; i++){if((*buff)[j] == i || (*(buff+1))[j] == i|| (*(buff+2))[j] == i|| (*(buff+3))[j] == i){cnt++;}}if(cnt != 4){return 0;}}return 1;
} int** SolvePuzzle (int *clues) {AssNode Assemble[24];int **out;int colbuf[4] = {0};int col; int i,j,k,z;int ii,jj;//printf("AAA\n");out = malloc(sizeof(int*) * 4);for(i=0; i<4; i++){*(out+i) = malloc(sizeof(int) * 4);}Get4X4Assemble(Assemble); /*第一行*/ for(i=0; i<24; i++){/*找到一个符合行要求的组合*/if((clues[15] == 0 || Assemble[i].LeftViewCnt == clues[15]) && (clues[4] == 0 || Assemble[i].RightViewCnt == clues[4])){memcpy(*out, Assemble[i].Valuegroup, 4*sizeof(int));//printf("AAb\n");/*第二行*/ for(j=0; j<24; j++){/*找到一个符合行要求的组合*/if((clues[14] == 0 || Assemble[j].LeftViewCnt == clues[14]) && (clues[5] == 0 || Assemble[j].RightViewCnt == clues[5])){memcpy(*(out+1), Assemble[j].Valuegroup, 4*sizeof(int));/*第三行*/for(k=0; k<24; k++){/*找到一个符合行要求的组合*/if((clues[13] == 0 || Assemble[k].LeftViewCnt == clues[13]) && (clues[6] == 0 || Assemble[k].RightViewCnt == clues[6])){memcpy(*(out+2), Assemble[k].Valuegroup, 4*sizeof(int));//printf("AAc\n");/*第四行*/for(z=0; z<24; z++){/*找到一个符合行要求的组合*/if((clues[12] == 0 || Assemble[z].LeftViewCnt == clues[12]) && (clues[7] == 0 || Assemble[z].RightViewCnt == clues[7])){memcpy(*(out + 3), Assemble[z].Valuegroup, 4*sizeof(int));/*校验列是否正确*/if(!IsColumeOrder(out)) continue;for(col=0; col<4; col++){colbuf[0] = out[0][col];colbuf[1] = out[1][col];colbuf[2] = out[2][col];colbuf[3] = out[3][col];//printf("AAd\n");if(!((clues[col] == 0 || clues[col] == GetLeftViewCnt(colbuf, 4))&& (clues[11-col] == 0 || clues[11-col] == GetRightViewCnt(colbuf, 4)))){/*校验列不正确,终止校验*//*printf("Err: i=%d, j=%d, k=%d, z=%d\n", i,j,k,z);printf("Err: Left=%d, right=%d, clues[col]=%d, clues[11-col]=%d\n", GetLeftViewCnt(colbuf, 4),GetRightViewCnt(colbuf, 4), clues[col], clues[11-col]);for(ii=0; ii<4; ii++){for(jj=0; jj<4; jj++){printf("%d ", out[ii][jj]);}printf("\n");}*/break; }}if(col == 4){/*找到答案,返回*//*printf("Get: i=%d, j=%d, k=%d, z=%d\n", i,j,k,z);for(ii=0; ii<4; ii++){for(jj=0; jj<4; jj++){printf("%d ", out[ii][jj]);}printf("\n");}*/return out; }}} }} }} }}//printf("return 0: i=%d, j=%d, k=%d, z=%d\n", i,j,k,z);return 0;
}