#include #include #include #include #include #include // 内部定数 #define D_LEN_MAX 8 // 最大文字数 #define D_STACK_MAX 10000 // 最大スタック数 #define D_TREE_MAX 50000 // 木の最大データ数 #define D_TREE_WCNT 2 // 木の方向数 #define D_TREE_LEFT 0 // 木の方向 - 左側 #define D_TREE_RIGHT 1 // 木の方向 - 右側 // 内部構造体 - スタック情報 typedef struct Stack { char mc1Str[D_LEN_MAX + 5]; // 文字列 } Stack; // 内部構造体 - 木構造 typedef struct Tree { char mc1Str[D_LEN_MAX + 5]; // 文字列 int mi1Height[D_TREE_WCNT]; // 木の高さ struct Tree *mzp1Child[D_TREE_WCNT]; // 子 } Tree; // 内部変数 static FILE *szpFpI; // 入力 static int siLen; // 文字列長 static Stack sz1Stack[D_STACK_MAX]; // スタック static int siSCnt; // スタック数 static int siSSNo; // スタック位置 - セット static int siSGNo; // スタック位置 - 取得 static Tree sz1Tree[D_TREE_MAX]; // 木の実データ static int siTCnt; // 木の実データ数 static Tree *szpTop; // 先頭の木データ // 内部変数 - テスト用 #ifdef D_TEST static int siRes; static FILE *szpFpA; #endif // 改行カット // 戻り値:文字数 int fCutCrLf( char *pcpStr // 文字列 ) { int i; for (i = 0; pcpStr[i] != '\0'; i++) { if (pcpStr[i] == '\n') { pcpStr[i] = '\0'; break; } } return i; } // スタック - セット int fStackSet( char *pcpStr // 文字列 ) { // セット strcpy(sz1Stack[siSSNo].mc1Str, pcpStr); // スタック数 siSCnt++; // スタック位置 - セット if (siSSNo < D_STACK_MAX - 1) { siSSNo++; } else { siSSNo = 0; } return 0; } // スタック - 取得 int fStackGet( Stack *pzpRet // 取得値 ) { // スタック数 if (siSCnt < 1) { return -1; } siSCnt--; // 取得 memcpy(pzpRet, &sz1Stack[siSGNo], sizeof(Stack)); // スタック位置 - 取得 if (siSGNo < D_STACK_MAX - 1) { siSGNo++; } else { siSGNo = 0; } return 0; } // 木データ - 作成 Tree * fTreeMake( char *pcpStr // 文字列 ) { // 対象の木データ Tree *lzpTree = &(sz1Tree[siTCnt]); siTCnt++; // データセット memset(lzpTree, 0, sizeof(Tree)); // 初期化 strcpy(lzpTree->mc1Str, pcpStr); // 文字列 return lzpTree; } // 木データ - 比較 int fTreeCmp( Tree *pzpTree // 木データ , char *pcpStr // 文字列 ) { return strcmp(pzpTree->mc1Str, pcpStr); } // 木データ - 検索 Tree * fTreeSrh( char *pcpStr // 文字列 ) { // 先頭の木データ Tree *lzpNow = szpTop; // 検索 while (1) { // データ有無 if (lzpNow == NULL) { return NULL; } // 比較 int liRet = fTreeCmp(lzpNow, pcpStr); if (liRet == 0) { // 一致 return lzpNow; } // 子へ移動 if (liRet < 0) { // 左側 lzpNow = lzpNow->mzp1Child[D_TREE_LEFT]; } else { // 右側 lzpNow = lzpNow->mzp1Child[D_TREE_RIGHT]; } } return NULL; } // 木データ - 高さ取得 int fTreeGetHeight( Tree *pzpTree // 対象の木情報 ) { // データ有無 if (pzpTree == NULL) { return 0; } if (pzpTree->mi1Height[D_TREE_LEFT] >= pzpTree->mi1Height[D_TREE_RIGHT]) { return pzpTree->mi1Height[D_TREE_LEFT] + 1; } else { return pzpTree->mi1Height[D_TREE_RIGHT] + 1; } } // 木データ - 右回転(親は子の右下へ・子は親の左上へ) int fTreeRttR( Tree **pzppTree // 回転対象 ) { // 現在の子 Tree *lzpChild = (*pzppTree)->mzp1Child[D_TREE_LEFT]; // 右回転 (*pzppTree)->mzp1Child[D_TREE_LEFT] = lzpChild->mzp1Child[D_TREE_RIGHT]; // 親の左側 = 子の右側 (*pzppTree)->mi1Height[D_TREE_LEFT] = lzpChild->mi1Height[D_TREE_RIGHT]; // 親の高さ(左) = 子の高さ(右) lzpChild->mzp1Child[D_TREE_RIGHT] = *pzppTree; // 子の右側 = 親 lzpChild->mi1Height[D_TREE_RIGHT] = fTreeGetHeight(*pzppTree); // 子の高さ(右) - 親の高さ *pzppTree = lzpChild; // 親 = 子 return 0; } // 木データ - 左回転(親は子の左下へ・子は親の右上へ) int fTreeRttL( Tree **pzppTree // 回転対象 ) { // 現在の子 Tree *lzpChild = (*pzppTree)->mzp1Child[D_TREE_RIGHT]; // 左回転 (*pzppTree)->mzp1Child[D_TREE_RIGHT] = lzpChild->mzp1Child[D_TREE_LEFT]; // 親の右側 = 子の左側 (*pzppTree)->mi1Height[D_TREE_RIGHT] = lzpChild->mi1Height[D_TREE_LEFT]; // 親の高さ(右) = 子の高さ(左) lzpChild->mzp1Child[D_TREE_LEFT] = *pzppTree; // 子の左側 = 親 lzpChild->mi1Height[D_TREE_LEFT] = fTreeGetHeight(*pzppTree); // 子の高さ(左) - 親の高さ *pzppTree = lzpChild; // 親 = 子 return 0; } // 木データ - 追加・削除の共通処理 // 戻り値:[1]高さの変更あり [0]高さの変更なし int fTreeComAddDel( Tree **pzppNow // 現在の木情報 , int piWay // 対象の方向 ) { // 高さの変更があるかチェック int liNew = fTreeGetHeight((*pzppNow)->mzp1Child[piWay]); if ((*pzppNow)->mi1Height[piWay] == liNew) { // 変化なし return 0; } (*pzppNow)->mi1Height[piWay] = liNew; // 更新 // 高さが離れている場合、回転 if ((*pzppNow)->mi1Height[D_TREE_LEFT] - (*pzppNow)->mi1Height[D_TREE_RIGHT] > 1) { // 左側が高い fTreeRttR(pzppNow); // 右回転 } else if ((*pzppNow)->mi1Height[D_TREE_RIGHT] - (*pzppNow)->mi1Height[D_TREE_LEFT] > 1) { // 右側が高い fTreeRttL(pzppNow); // 左回転 } return 1; } // 木データ - 追加 // 戻り値:[1]高さの変更あり [0]高さの変更なし [-1]追加なし int fTreeAdd( Tree **pzppNow // 現在の木情報 , char *pcpStr // 文字列 ) { // 作成 if (*pzppNow == NULL) { *pzppNow = fTreeMake(pcpStr); return 1; } // 比較 int liRet = fTreeCmp(*pzppNow, pcpStr); // 一致 if (liRet == 0) { return -1; } // 方向の判別 int liWay; if (liRet < 0) { // 左側 liWay = D_TREE_LEFT; } else { // 右側 liWay = D_TREE_RIGHT; } // 下位へ liRet = fTreeAdd(&((*pzppNow)->mzp1Child[liWay]), pcpStr); if (liRet < 1) { // 高さの変更なし or 追加なし return liRet; } // 追加・削除の共通処理 return fTreeComAddDel(pzppNow, liWay); } // 文字 - 入れ替え int fSwap( char *pcpVal1 // 文字1 , char *pcpVal2 // 文字2 ) { char lcWork = *pcpVal1; *pcpVal1 = *pcpVal2; *pcpVal2 = lcWork; return 0; } // 実行メイン int fMain( int piTNo // テスト番号 1~ ) { int i, liRet; char lc1Buf[1024], lc1Out[1024]; // データ - 初期化 siSCnt = 0; // スタック数 siSSNo = 0; // スタック位置 - セット siSGNo = 0; // スタック位置 - 取得 siTCnt = 0; // 木の実データ数 szpTop = NULL; // 先頭の木データ // 入力 - セット #ifdef D_TEST sprintf(lc1Buf, ".\\Test\\T%d.txt", piTNo); szpFpI = fopen(lc1Buf, "r"); sprintf(lc1Buf, ".\\Test\\A%d.txt", piTNo); szpFpA = fopen(lc1Buf, "r"); siRes = 0; #else szpFpI = stdin; #endif // 文字列 - 取得 fgets(lc1Buf, sizeof(lc1Buf), szpFpI); // 改行カット siLen = fCutCrLf(lc1Buf); // スタック - セット if (siLen > 1) { fStackSet(lc1Buf); } else { siTCnt = 1; } while (1) { // スタック - 取得 Stack lzStack; liRet = fStackGet(&lzStack); if (liRet != 0) { break; } // 文字の入れ替え for (i = 0; i < siLen - 1; i++) { char lc1Str[D_LEN_MAX + 5]; strcpy(lc1Str, lzStack.mc1Str); fSwap(&lc1Str[i], &lc1Str[i + 1]); // 木 - 検索 Tree *lzpTree = fTreeSrh(lc1Str); if (lzpTree != NULL) { // 登録済 continue; } // 木 - 追加 fTreeAdd(&szpTop, lc1Str); // スタック - セット fStackSet(lc1Str); } } // 結果 - セット sprintf(lc1Out, "%d\n", siTCnt - 1); // 結果 - 表示 #ifdef D_TEST fgets(lc1Buf, sizeof(lc1Buf), szpFpA); if (strcmp(lc1Buf, lc1Out)) { siRes = -1; } #else printf("%s", lc1Out); #endif // 残データ有無 #ifdef D_TEST lc1Buf[0] = '\0'; fgets(lc1Buf, sizeof(lc1Buf), szpFpA); if (strcmp(lc1Buf, "")) { siRes = -1; } #endif // テストファイルクローズ #ifdef D_TEST fclose(szpFpI); fclose(szpFpA); #endif // テスト結果 #ifdef D_TEST if (siRes == 0) { printf("OK %d\n", piTNo); } else { printf("NG %d\n", piTNo); } #endif return 0; } int main() { #ifdef D_TEST int i; for (i = D_TEST_SNO; i <= D_TEST_ENO; i++) { fMain(i); } #else fMain(0); #endif return 0; }