hdu 5811 Colosseo (拓扑排序 + 最长上升子序列)

15 篇文章 0 订阅

Colosseo

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 645    Accepted Submission(s): 130


Problem Description
Mr. Chopsticks keeps N monsters, numbered from 1 to N. In order to train them, he holds N * (N - 1) / 2 competitions and asks the monsters to fight with each other. Any two monsters fight in exactly one competition, in which one of them beat the other. If monster A beats monster B, we say A is stronger than B. Note that the “stronger than” relation is not transitive. For example, it is possible that A beats B, B beats C but C beats A.

After finishing all the competitions, Mr. Chopsticks divides all the monsters into two teams T1 and T2, containing M and N – M monsters respectively, where each monster is in exactly one team. Mr. Chopsticks considers a team of monsters powerful if there is a way to arrange them in a queue (A1, A2, …, Am) such that monster Ai is stronger than monster Aj for any 1<=i<j<=m. Now Mr. Chopsticks wants to check whether T1 and T2 are both powerful, and if so, he wants to select k monsters from T2 to join T1 such that the selected monsters together with all the monsters in T1 can still form a powerful team and k is as large as possible. Could you help him?
 

Input
The input contains multiple test cases. Each case begins with two integers N and M (2 <= N <= 1000, 1 <= M < N), indicating the number of monsters Mr. Chopsticks keeps and the number of monsters in T1 respectively. The following N lines, each contain N integers, where the jth integer in the ith line is 1 if the ith monster beats the jth monster; otherwise, it is 0. It is guaranteed that the ith integer in the jth line is 0 iff the jth integer in the ith line is 1. The ith integer in the ith line is always 0. The last line of each case contains M distinct integers, each between 1 and N inclusively, representing the monsters in T1. The input is terminated by N = M = 0.
 

Output
For each case, if both T1 and T2 are powerful, output “YES” and the maximum k; otherwise, output “NO”.
 

Sample Input
  
  
3 2 0 1 1 0 0 1 0 0 0 3 1 4 3 0 1 0 1 0 0 1 1 1 0 0 1 0 0 0 0 1 2 3 4 2 0 1 0 1 0 0 1 1 1 0 0 1 0 0 0 0 1 2 0 0
 

Sample Output
  
  
YES 1 NO YES 1
Hint
In the third example, Mr. Chopsticks can let the monster numbered 4 from T2 join into T1 to form a queue (1, 2, 4).
 


这题的输入  ...!!

对T1 和 T2 分别做次拓扑排序 把两个序列记录下来

如果两个都不成环 就是 YES 的情况

否则就是 NO

对YES的情况 按排好的拓扑序把 T2的元素 分别判断 能否加入T1 能的话 记录位置

最后对  位置数组 求最长上升子序列 (不严格递增)


#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cctype>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#define pi acos(-1.0)
#define inf 1<<29
#define INF 0x3fffffff
#define zero 1e-8

const int li[] = { -1, 0, 1, 0};
const int lj[] = {0, -1, 0, 1};

using namespace std;

const int N = 1000 + 107;

int t1[N], t2[N];
int edge[N][N];
bool r1[N], r2[N], flag1[N], flag2[N];
int Rank[N], sum1[N], sum2[N];
int n, t;

int que1[N], que2[N], head1, head2, tail1, tail2;
int id1[N], id2[N];

void show(int *id, int t, int flag)
{
    for (int i = 0; i <= t; ++i)
        cout << "id " << flag << ": " << id[i] << endl;
}

void init()
{
    memset(sum1, 0, sizeof(sum1));
    memset(sum2, 0, sizeof(sum2));
    memset(flag1, 0, sizeof(flag1));
    memset(flag2, 0, sizeof(flag2));
    memset(Rank, 0, sizeof(Rank));
    memset(t1, 0, sizeof(t1));
    memset(t2, 0, sizeof(t2));
    memset(r1, 0, sizeof(r1));
    memset(r2, 0, sizeof(r2));
}
bool judge()
{

    int j = 0;
    tail1 = tail2 = head1 = head2 = 0;

    for (int i = 1; i <= N; ++i)
        if (!r1[i]) {
            t2[j++] = i;
            r2[i] = true;
        }

    for (int i = 0; i < t; ++i) {
        for (int j = 1; j <= n; ++j)
            if (r1[j] && j != t1[i]) {
                sum1[t1[i]] += !edge[t1[i]][j];

            }
        if (!sum1[t1[i]]) que1[tail1++] = t1[i], flag1[t1[i]] = true;
    }
    for (int i = 0; i < n - t; ++i) {
        for (int j = 1; j <= n; ++j)
            if (r2[j] && j != t2[i]) sum2[t2[i]] += !edge[t2[i]][j];
        if (!sum2[t2[i]]) que2[tail2++] = t2[i], flag2[t2[i]] = true;
    }
    int w = 0;

    for (; head1 < tail1; head1++) {
        id1[++w] = que1[head1];
        for (int j = 1; j <= n; ++j)
            if (r1[j] && j != que1[head1]) {
                if (edge[que1[head1]][j])
                    sum1[j] -= 1;
                if (!sum1[j] && !flag1[j]) {
                    que1[tail1++] = j;
                    flag1[j] = true;
                }
            }
    }
    if (tail1 != t) return false;
    w = 0;
    for (; head2 < tail2; head2++) {
        id2[++w] = que2[head2];
        for (int j = 1; j <= n; ++j)
            if (r2[j] && j != que2[head2]) {
                if (edge[que2[head2]][j])
                    sum2[j] -= 1;
                if (!sum2[j] && !flag2[j]) {
                    que2[tail2++] = j;
                    flag2[j] = true;
                }
            }
    }

    if (tail2 != n - t) return false;
    return true;
}

int sta[N];
int maxup(int cnt)
{
    memset(sta, 0, sizeof(sta));
    int top = 0;

    for (int i = 0; i < cnt; ++i) {
        int maxx = 0;
        for (int j = 1; j <= Rank[i]; ++j) {
            maxx = maxx > sta[j] ? maxx : sta[j];
        }
        sta[Rank[i]] = maxx + 1;
        top = top > sta[Rank[i]] ? top : sta[Rank[i]];
    }

    return top;
}
int DO()
{
    int cnt = 0;
    for (int i = 1; i <= n - t; ++i) {
        int tag;
        bool flag = 0, tip = 0;
        for (int j = t; j > 0; --j) {
            if (edge[id2[i]][id1[j]]) {
                if (flag) {
                    tip = 1;
                    break;
                }
                tag = j - 1;
            }
            if (edge[id1[j]][id2[i]] && !flag) {
                tag = j;
                flag = true;
            }
        }
        if (!tip) {
            Rank[cnt++] = tag + 1;
        }
    }
    return maxup(cnt);
}

int read()
{
    int v = 0, f = 1;
    char c = getchar();
    while( c < 48 || 57 < c ) {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(48 <= c && c <= 57)
        v = v * 10 + c - 48, c = getchar();
    return v * f;
}
char str[N];

int main()
{

    while(~scanf("%d %d", &n, &t)) {


        if (!n && !t) break;
        init();
        getchar();
        for (int i = 1; i <= n; ++i) {
            gets(str);
            int kk = 0;
            for (int j = 1; j <= n; ++j, ++kk)
                edge[i][j] = str[kk++] - '0';;
        }
        int kk = 0;
        for (int i = 0; i < t; ++i) {
            t1[i] = read();
            r1[t1[i]] = true;
        }

        if (!judge()) printf("NO\n");
        else printf("YES %d\n", DO());
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值