描述
在路易十三和紅衣主教黎塞留當權的時代,發生了一場決鬥。n個人站成一個圈,依次抽籤。抽中的人和他右邊的人決鬥,負者出圈。這場決鬥的最終結果關鍵取決於決鬥的順序。現書籍任意兩決鬥中誰能勝出的資訊,但“A贏了B”這種關係沒有傳遞性。例如,A比B強,B比C強,C比A強。如果A和B先決鬥,C最終會贏,但如果B和C決鬥在先,則最後A會贏。顯然,他們三人中的第一場決鬥直接影響最終結果。
假設現在n個人圍成一個圈,按順序編上編號1~n。一共進行n-1場決鬥。第一場,其中一人(設i號)和他右邊的人(即i+1號,若i=n,其右邊人則為1號)。負者被淘汰出圈外,由他旁邊的人補上他的位置。已知n個人之間的強弱關係(即任意兩個人之間輸贏關係)。如果存在一種抽籤方式使第k個人可能勝出,則我們說第k人有可能勝出,我們的任務是根據n個人的強弱關係,判斷可能勝出的人數。
輸入
第一行是一個整數N(1<=N<=20)表示測試資料的組數。
第二行是一個整數n表示決鬥的總人數。(2<=n<=500)
隨後的n行是一個n行n列的矩陣,矩陣中的第i行第j列如果為1表示第i個人與第j個人決鬥時第i個人會勝出,為0則表示第i個人與第j個人決鬥時第i個人會失敗。
輸出
對於每組測試資料,輸出可能勝出的人數,每組輸出佔一行
範例輸入
1
3
0 1 0
0 0 1
1 0 0
範例輸出
3
這個題有些類似於弗洛伊德演算法,將環轉化為鏈,通過dp實現,vic[i][j]表示第i個人是否可以與第j個人存在pk機會,當i=j時,也就是出現了自己是否可以和自己pk,如果為真,則表示此環可以最後只剩下第i個人,所以他沒有下一個pk對象,只能和自己pk,否則,說明這個人不能和自己pk,也就是說,不會出現最後只剩下第i個人的情況。
具體代碼實現如下:
#include <stdio.h>#include <string.h>int vic[501][501]; //vic[i][j]第i個與第j個是否有機會PKint rel[501][501]; //劍客間的勝負關係//初始化void init(int n){ int i, j; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { scanf("%d", rel[i] + j); } } memset(vic, 0, sizeof(int) * 501 * 501); for (i = 0; i < n; i++) //初始化時只能確定相鄰的兩個人是可以PK的 { vic[i][(i + 1) % n] = 1; } return ;}int solve(int n){ int i, j, start, end; for (i = 1; i < n; i++) //中間隔著i個人 { for (start = 0; start < n; start++) { end = (start + i + 1) % n; if (vic[start][end]) //當確認兩個能PK時 { continue; } for (j = (start + 1) % n; j != end; j++, j %= n) { if (vic[start][j] && vic[j][end] && (rel[start][j] || rel[end][j])) //當start可以和jPK,j可以和endPK,並且至少有一方可以大過j方能實現start和endPK { vic[start][end] = 1; break; } } } } int cnt = 0; for (i = 0; i < n; i++) { if (vic[i][i]) //為1說明i可以勝出 { cnt++; } } return cnt;}int main(int argc, const char * argv[]){ int N, n; scanf("%d", &N); while (N--) { scanf("%d", &n); init(n); printf("%d\n", solve(n)); } return 0;}