NYOJ 110

哎,有个细节没注意到,一直折腾到现在!

    编号为i的人能从所有人中胜出,必要条件是他能与自己“相遇”,即把环看成链,x点拆成两个在这条链的两端,中间的人全部被淘汰出局,x保持不败。这样,在连续几个人的链中,只须考虑头尾两个人能否胜利会师,中间的则不予考虑,从而少了一维状态表示量。设Meet_Matrix[i,j]记录i和j能否相遇,能相遇则为true,否则为false。Meet_Matrix[i][j] = true 的条件是中间存在 k 使得 Meet_Matrix[i][k] == true && Meet_Matrix[k][j] == true && i, j 至少有一个能战胜 k;也即是

if(Meet_Matrix[i][t] && Meet_Matrix[t][j] && (fight_Matrix[i][t] || fight_Matrix[j][t]=true) && i < t < j)
     Meet_Matrix[i][j] = true;
else
     Meet_Matrix[i][j] = falze;

#include <iostream>
#include <cstring>

using namespace std;

const int MAXN = 510;

int fight_Matrix[MAXN][MAXN];
bool Meet_Matrix[MAXN][MAXN];


int main()
{
    int T;
    int n;
    cin>>T;
    while(T--)
    {
        cin>>n;
       // memset(fight_Matrix, 0, sizeof(fight_Matrix));
        for(int i = 0; i < n; ++i)
            for(int j = 0; j < n; ++j)
                cin>>fight_Matrix[i][j];

        memset(Meet_Matrix, false, sizeof(Meet_Matrix));

        for(int i = 0; i < n; ++i)//相邻两个剑客是能相遇的
            Meet_Matrix[i][(i+1)%n] = true;

        for(int k = 1; k < n; ++k)//两个剑客中间相隔k个人
        {
            for(int start = 0; start < n; ++start)
            {
                int last = (start + k + 1) % n;//与start相隔k个人的剑客。
                if(Meet_Matrix[start][last])//如果这两个剑客已经比试过了,则继续。
                    continue ;
                for(int t = (start+1)%n; t != last; ++t,t%=n)//此处中间那个剑客t,要么是last要么不是,因此是t != last
                {
                    if(Meet_Matrix[start][t] && Meet_Matrix[t][last] && (fight_Matrix[start][t] || fight_Matrix[last][t]))
                    {
                        Meet_Matrix[start][last] = true;
                        break;
                    }
                }
            }
        }
        int Kcount = 0;
        for(int i = 0; i < n; ++i)
        {
            if(Meet_Matrix[i][i] == true)
                Kcount++;
        }
        cout<<Kcount<<endl;
    }
    return 0;
}


你可能感兴趣的:(NYOJ 110)