【HDU 5811】Colosseo(拓扑+输入优化)

【HDU 5811】Colosseo(拓扑+输入优化)

Colosseo

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

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).

Author

SYSU

Source

2016 Multi-University Training Contest 7

题目大意:

Chopsticks养了n只怪兽。他们有制约关系,用一个矩阵mat表示。

matij=1表示i怪物能打败j怪物,同时对称位置matji=0

matij=0表示i怪物打不过j怪物,同时对称位置matji=1

matii=0

要注意制约关系不具备传递性,例如可以有A能打败B B能打败C C能打败A的情况。

现在Chop挑选出m只怪兽组成T1队,剩下n-m只怪兽组成T2队

询问T1队与T2队是否合法

合法是指存在某种排列a1,a2,a3,...,ak满足mataiaj=1(i<j)

排列中任意一只怪兽都能打败他右边所有怪兽。

然后问最多从T2中能选出几只怪兽插入到T1中,能保证T1依旧合法?

第一个判断用拓扑排序即可,什么姿势都可以。

如果是YES,可以在拓扑排序中找到两个队伍的拓扑序。在T2的拓扑序列中从低到高(最弱的怪兽到能打败T2中所有怪兽的怪兽)遍历,在T1中找到它可以放置的位置,可知这个位置是固定的!,否则就不能放入T1

然后找到最长上升/下降子序列,这个取决于很多因素,比如拓扑序存储方式,遍历方式等等

然后测试通过,兴高采烈的提交…………………………

Surprise!!TLE……

憋动手。。。并不是算法有误,改一下输入试试。。。scanf(“%d”)1000*1000本题会爆炸(其实本地测后台数据并没爆……)

改成gets,然后从字符串中得到数字即可,因为只有1和0,用下标。

神题啊…………

代码如下:

#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)

using namespace std;
const int INF = 0x3f3f3f3f;
const int msz = 10000;
const int mod = 1e9+7;
const double eps = 1e-8;

int mp[1111][1111];
int in[1111];
int team[1111];
int vc[2][1111];
int n,m,tp[2];

bool topo()
{
    memset(in,0,sizeof(in));
    int u,v;

    for(int i = 1; i <= n; ++i)
    {
        for(int j = i+1; j <= n; ++j)
        {
            if(team[i] != team[j]) continue;
            if(mp[i][j]) in[j]++;
            if(mp[j][i]) in[i]++;
        }
    }

    for(int i = 1; i <= n; ++i)
    {
        for(u = 1; u <= n; ++u)
            if(!in[u]) break;

        if(u == n+1) return false;
        in[u]--;
        vc[team[u]][tp[team[u]]++] = u;

        for(v = 1; v <= n; ++v)
        {
            if(mp[u][v] && team[u] == team[v])
                in[v]--;
        }

    }

    return true;
}

int dp[1111];

void Search(int l,int &len,int x)
{
    int r = len;

    int ans = -1;
    while(l <= r)
    {
        int mid = (l+r)>>1;
        if(dp[mid] <= x) l = mid+1;
        else
        {
            ans = mid;
            r = mid-1;
        }
    }
    if(ans == -1) ans = len++;
    dp[ans] = x;
}

int solve()
{
    int len = 0;
    memset(dp,0,sizeof(dp));

    int u,v;
    for(int i = 0; i < tp[0]; ++i)
    {
        int pos = 1;
        u = vc[0][i];
        //printf("%d:\n",u);

        for(int j = tp[1]-1; j >= 0; --j)
        {
            v = vc[1][j];
            //printf("%d->%d %d\n",v,u,mp[v][u]);
            if(mp[v][u])
            {
                if(pos <= 1) pos = j+2;
            }
            else if(pos != 1)
            {
                pos = -1;
                break;
            }
        }

        //printf("%d\n---------\n",pos);
        if(pos == -1) continue;
        Search(0,len,pos);
    }

    return len;
}

//#include <ctime>
char str[2333];
int main()
{
    //double x = clock();
    //fread("1003.in");
    //fwrite("test.out");

    while(~scanf("%d%d\n",&n,&m) && (n+m))
    {
        tp[0] = tp[1] = 0;
        for(int i = 1; i <= n; ++i)
        {
            gets(str);
            for(int j = 1; j <= n; ++j)
            {
                char ch = str[j*2-2];
                mp[i][j] = ch-‘0‘;
            }
        }

        int x;
        memset(team,0,sizeof(team));
        for(int i = 0; i < m; ++i)
        {
            scanf("%d",&x);
            team[x] = 1;
        }

        if(!topo())
        {
            puts("NO");
            continue;
        }
        printf("YES %d\n",solve());
    }

    //printf("%f\n",(clock()-x)/CLOCKS_PER_SEC);

    return 0;
}
时间: 2024-10-19 04:19:11

【HDU 5811】Colosseo(拓扑+输入优化)的相关文章

HDU 5811 Colosseo

首先判断一下两个集合是否能够拓扑排序,顺便记录下每个节点的拓扑序. 然后看T2中每个点在T1中能够放在哪一个位置,记录下这个位置Pi. 然后T2中(按拓扑序排好),计算Pi的一个非严格递增的LIS.LIS长度就是答案. 这题scanf读入都900+ms了,有时直接卡TLE.改用gets整行读入,时间上会有很大改进. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #includ

HDU - 6178:Monkeys (贪心&amp;树上最大匹配输&amp;输入优化)

There is a tree having N vertices. In the tree there are K monkeys (K <= N). A vertex can be occupied by at most one monkey. They want to remove some edges and leave minimum edges, but each monkey must be connected to at least one other monkey throug

hdu 4857 逆拓扑+大根堆(priority_queue)

题意:排序输出:在先满足定约束条件下(如 3必需在1前面,7必需在4前面),在满足:1尽量前,其次考虑2,依次.....(即有次约束). 开始的时候,只用拓扑,然后每次在都可以选的时候,优先考虑小的,其实没什么简单,如 图(3-->1,2)这样输出是2.3.1,正确应该是 3 1 2,因为 1要尽量前(都满足第一约束). 参考他人思路结合自己理解:因为这样的弊端就是没有考虑这种情况:图中:若我的"子孙"中,有的比你次优先,虽然现在我们都可以输出,但是要考虑我的子代,若我的子代有次

HDU 1059 多重背包+二进制优化

Dividing Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 16909    Accepted Submission(s): 4729 Problem Description Marsha and Bill own a collection of marbles. They want to split the collection

HDU 3507 Print Article 斜率优化

Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 4810    Accepted Submission(s): 1451 Problem Description Zero has an old printer that doesn't work well sometimes. As it is antique

hdu 2647 Reward (拓扑排序分层)

Reward Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3815    Accepted Submission(s): 1162 Problem Description Dandelion's uncle is a boss of a factory. As the spring festival is coming , he wa

HDU 3507 单调队列 斜率优化

斜率优化的模板题 给出n个数以及M,你可以将这些数划分成几个区间,每个区间的值是里面数的和的平方+M,问所有区间值总和最小是多少. 如果不考虑平方,那么我们显然可以使用队列维护单调性,优化DP的线性方法来做,但是该题要求的是区间和的平方,于是要转换单调的计算方法为斜率,也就是凸线. 其他就是最基本的单调DP /** @Date : 2017-09-04 15:39:05 * @FileName: HDU 3507 单调队列 斜率优化 DP.cpp * @Platform: Windows * @

hdu 3480 Division (斜率优化)

Division Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 999999/400000 K (Java/Others) Total Submission(s): 2676    Accepted Submission(s): 1056 Problem Description Little D is really interested in the theorem of sets recently. There's a pro

HDU 4917 Permutation 拓扑排序的计数

题意: 一个有n个数的排列,给你一些位置上数字的大小关系.求合法的排列有多少种. 思路: 数字的大小关系可以看做是一条有向边,这样以每个位置当点,就可以把整个排列当做一张有向图.而且题目保证有解,所以只一张有向无环图.这样子,我们就可以把排列计数的问题转化为一个图的拓扑排序计数问题. 拓扑排序的做法可以参见ZJU1346 . 因为题目中点的数量比较多,所以无法直接用状压DP. 但是题目中的边数较少,所以不是联通的,而一个连通块的点不超过21个,而且不同连通块之间可以看做相互独立的.所以我们可以对