プログラムの実行結果は以下の通り。
Convex:3656 発見 [330]a: 1,b: 3,c: 8,d: 9, bits: 185, d1:10,d2:20,d3:25,d4:25,35 [332]a: 2,b: 6,c: 7,d:11, bits: 462, d1:10,d2:20,d3:25,d4:25,35 [333]a: 4,b: 5,c:10,d:12, bits: a18, d1:10,d2:20,d3:25,d4:25,35
図示すると以下の通り。
プログラムのソースは以下の通り。
#include "puzutl.h" struct xy { // 図の点 int x; int y; } data[] = { { 0, 0}, // 点の番号をINDEXで使いたいので最初はDUMMY { 1, 8}, // 1 { 6, 8}, // 2 { 5, 6}, // 3 { 0, 5}, // 4 { 5, 5}, // 5 { 3, 4}, // 6 { 8, 4}, // 7 { 1, 3}, // 8 { 6, 3}, // 9 { 3, 1}, // 10 { 7, 1}, // 11 { 0, 0}, // 12 { 5, 0}, // 13 }; struct rect { int a, b, c, d; // 四角形を構成する4点(data[]のINDEX値,ソートして記録) int bits; // 四角形を構成する点をビット位置で記録,3つの四角形の点が重複しないことを高速に確認するため int d1, d2, d3, d4; // 辺長(ソートして記録) int menseki; // 四角形の面積 } rect[5000]; // 凸四角形の数は3656個 int nrect; int bit[] = { 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192}; YesNo used[1+13]; int cmpint(const void *p1, const void *p2) // qsort()の比較関数 { return *(int*)p1 - *(int*)p2; } int cmprect( const void *p1, const void *p2) // qsort()の比較関数 { const struct rect* v1 = (const struct rect*)p1; const struct rect* v2 = (const struct rect*)p2; if( v1->d1 != v2->d1) return v1->d1 - v2->d1; if( v1->d2 != v2->d2) return v1->d2 - v2->d2; if( v1->d3 != v2->d3) return v1->d3 - v2->d3; if( v1->d4 != v2->d4) return v1->d4 - v2->d4; if( v1->menseki != v2->menseki) return v1->menseki - v2->menseki; if( v1->a != v2->a) return v1->a - v2->a; if( v1->b != v2->b) return v1->b - v2->b; if( v1->c != v2->c) return v1->c - v2->c; if( v1->d != v2->d) return v1->d - v2->d; return 0; } void dupout() // 同一データを除去する { int n = 0; struct rect prev = {0}; if( nrect < 1) return; for( int i=1; i< nrect; i++) { if( rect[i].a != rect[n].a || rect[i].b != rect[n].b || rect[i].c != rect[n].c || rect[i].d != rect[n].d || rect[i].d1 != rect[n].d1 || rect[i].d2 != rect[n].d2 || rect[i].d3 != rect[n].d3 || rect[i].d4 != rect[n].d4 || rect[i].menseki != rect[n].menseki) { rect[++n] = rect[i]; } } nrect = n+1; } int calcmenseki2( int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy) { int dx1 = bx - ax; int dy1 = by - ay; int dx2 = cx - ax; int dy2 = cy - ay; int dx3 = dx - ax; int dy3 = dy - ay; int tri1 = dx1*dy2 - dy1*dx2; int tri2 = dx2*dy3 - dy2*dx3; return abs(tri1) + abs(tri2); } int checkpoint( int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy) { int dbx = bx - ax; int dby = by - ay; int dcx = cx - ax; int dcy = cy - ay; int ddx = dx - ax; int ddy = dy - ay; int dc = dbx*dcy - dby*dcx; int dd = dbx*ddy - dby*ddx; if( dc > 0 && dd > 0) return 1; else if( dc > 0 && dd < 0) return -1; else if( dc < 0 && dd > 0) return -1; else return 0; } int calcinfo( int a, int b, int c, int d) { // 辺の長さを計算する。 int dx1 = data[b].x - data[a].x; int dy1 = data[b].y - data[a].y; int dx2 = data[c].x - data[b].x; int dy2 = data[c].y - data[b].y; int dx3 = data[d].x - data[c].x; int dy3 = data[d].y - data[c].y; int dx4 = data[a].x - data[d].x; int dy4 = data[a].y - data[d].y; int d1 = dx1*dx1 + dy1*dy1; int d2 = dx2*dx2 + dy2*dy2; int d3 = dx3*dx3 + dy3*dy3; int d4 = dx4*dx4 + dy4*dy4; int abcd[4] = { a, b, c, d}; qsort( abcd, 4, sizeof(int), cmpint); int dd[4] = { d1, d2, d3, d4}; qsort( dd, 4, sizeof(int), cmpint); rect[nrect].a = abcd[0]; rect[nrect].b = abcd[1]; rect[nrect].c = abcd[2]; rect[nrect].d = abcd[3]; rect[nrect].bits = bit[a]+bit[b]+bit[c]+bit[d]; rect[nrect].d1 = dd[0]; rect[nrect].d2 = dd[1]; rect[nrect].d3 = dd[2]; rect[nrect].d4 = dd[3]; rect[nrect].menseki = calcmenseki2( data[a].x, data[a].y, data[b].x, data[b].y, data[c].x, data[c].y, data[d].x, data[d].y); nrect++; return d1+d2+d3+d4; } int isConvex( int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy) { return checkpoint( ax, ay, cx, cy, bx, by, dx, dy) < 0 && checkpoint( bx, by, dx, dy, ax, ay, cx, cy) < 0; } YesNo isConvex( int a, int b, int c, int d) { return isConvex( data[a].x, data[a].y, data[b].x, data[b].y, data[c].x, data[c].y, data[d].x, data[d].y); } void checkall( int idx, int same) { idx -= same; for( int i=0; i< same; i++) { for( int j=i+1; j< same; j++) { for( int k=j+1; k< same; k++) { if( (rect[idx+i].bits & rect[idx+j].bits) || (rect[idx+j].bits & rect[idx+k].bits) || (rect[idx+k].bits & rect[idx+i].bits)) { } else if( rect[idx+i].menseki == rect[idx+j].menseki && rect[idx+j].menseki == rect[idx+k].menseki ) { ps( "発見\n"); ps( "[%d]a:%2d,b:%2d,c:%2d,d:%2d, bits:%4x, d1:%2d,d2:%2d,d3:%2d,d4:%2d,%2d\n", idx+i, rect[idx+i].a, rect[idx+i].b, rect[idx+i].c, rect[idx+i].d, rect[idx+i].bits, rect[idx+i].d1, rect[idx+i].d2, rect[idx+i].d3, rect[idx+i].d4, rect[idx+i].menseki); ps( "[%d]a:%2d,b:%2d,c:%2d,d:%2d, bits:%4x, d1:%2d,d2:%2d,d3:%2d,d4:%2d,%2d\n", idx+j, rect[idx+j].a, rect[idx+j].b, rect[idx+j].c, rect[idx+j].d, rect[idx+j].bits, rect[idx+j].d1, rect[idx+j].d2, rect[idx+j].d3, rect[idx+j].d4, rect[idx+j].menseki); ps( "[%d]a:%2d,b:%2d,c:%2d,d:%2d, bits:%4x, d1:%2d,d2:%2d,d3:%2d,d4:%2d,%2d\n", idx+k, rect[idx+k].a, rect[idx+k].b, rect[idx+k].c, rect[idx+k].d, rect[idx+k].bits, rect[idx+k].d1, rect[idx+k].d2, rect[idx+k].d3, rect[idx+k].d4, rect[idx+k].menseki); } } } } } int main( int argc, cstring argv[]) { int i; int cntConvex = 0; for( int a=1; a<= 13; a++) { used[a] = YES; for( int b=1; b<= 13; b++) { if( used[b]) continue; used[b] = YES; for( int c=1; c<= 13; c++) { if( used[c]) continue; used[c] = YES; for( int d=1; d<= 13; d++) { if( used[d]) continue; if( isConvex( a, b, c, d)) { calcinfo(a,b,c,d); cntConvex++; } used[d] = NO; } used[c] = NO; } used[b] = NO; } used[a] = NO; } qsort( rect, nrect, sizeof(rect[0]), cmprect); dupout(); ps( "Convex:%d\n", cntConvex); #if 0 for( i=0; i< nrect; i++) { ps( "%4d : %2d,%2d,%2d,%2d,辺長(%3d, %3d, %3d, %3d)面積(%4d)\n", i, rect[i].a, rect[i].b, rect[i].c, rect[i].d, rect[i].d1, rect[i].d2, rect[i].d3, rect[i].d4, rect[i].menseki); } #endif int same = -1; struct rect prev; prev.d1 = prev.d2 = prev.d3 = prev.d4 = -1; for( i=0; i< nrect; i++) { if( rect[i].d1 != prev.d1 || rect[i].d2 != prev.d2 || rect[i].d3 != prev.d3 || rect[i].d4 != prev.d4) { if( same >= 3) { // 同じ四角形が3つなければならない checkall( i, same); } same = 1; prev = rect[i]; } else { same++; } } return 0; }