劍客決鬥
- 描述
-
在路易十三和紅衣主教黎塞留當權的時代,發生了一場決鬥。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[i][j] 表示i是否可以遇到j
問題轉化成了是否能在這條鏈中找到一個k,使得 i 和 k , k 和 j 均能相遇,且 i 或者 j 能打敗 k 。
狀態轉移方程是:dp[i,j] = true( 存在k∈鏈{i,j}使得meet[i,k]且meet[k,j]且(beat[i,k]或beat[j,k]) )
初始值dp[i,i+1] = true,計算順序依然是沿對角線的順序。
#include <stdio.h>
#include <string.h>
#define N 505
bool beat[N][N],meet[N][N];
int main()
{
int z,n;
scanf("%d",&z);
while(z--)
{
memset(meet,false,sizeof(meet));
scanf("%d",&n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&beat[i][j]);
for(int i=0;i<n-1;i++)
meet[i][i+1] = true;
meet[n-1][0] = true;
for(int d=2;d<=n;d++)
for(int i=0;i<n;i++)
{
int j = i+d;
for(int k=i+1;k<j;k++)
{
if(meet[i][k%n] && meet[k%n][j%n] && (beat[i][k%n] || beat[j%n][k%n]))
{
meet[i][j%n] = true;
break;
}
}
}
int ans = 0;
for(int i=0;i<n;i++)
if(meet[i][i])
++ans;
printf("%d\n",ans);
}
return 0;
}