HDU 5811 Colosseo

11 篇文章 0 订阅
2 篇文章 0 订阅

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?

Solution

终于知道为什么他们可以天天向我炫耀访问量了。。原来他们翻译了题目!!
这里写图片描述

这题奥妙重重,又是一道涨姿势题。。 竞赛图上get新技能,拓扑序。

那么首先我们对两个集合跑一遍拓扑排序,这样我们就可以得到 YES or NO 以及两个集合中元素的拓扑序
判断YES或NO的时候拓扑排序或者暴力 O(N2) 判断都可以.
接下来对于 T2 中的每个点,只需要在 T1 中扫一遍就可以判断出是否可以放进 T1 ,如果不能放进去就直接丢掉,如果可以就确定放在哪个位置.
注意因为是个竞赛图,所以这个位置是唯一的.
T2 剩下的点按在 T2 中的拓扑顺序(因为是竞赛图,所以这个顺序也是唯一的)标上它们在 T1 中的位置值,对得到的这个位置值数列求最长上升子序列的长度就是答案.
总复杂度 O(N2) .

来论述一下正确性
首先因为是竞赛图,两个子图也是竞赛图。
在没有还的情况下有且只有一个入度为0的点。
删掉一个点依旧是竞赛图。。
和上面那幅图神似。。这就可以说明为什么拓扑序是一定的

然后说说为什么答案是LIS
因为拓扑序在后的一定被更多人指向
并且是无环竞赛图,那么在后面的一定被在前面的指到。
诶!
为什么是LIS出来了,在保证在加入 T1 后无环, T2 的点在 T1 中也应当是一个上升序列,所以答案是LIS

懒得一逼。。LIS都 O(n2) 写。。

Code

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<time.h>
#include<stdlib.h>
#include<math.h>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef double db;
typedef unsigned ud;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vec;
typedef vector<pii> vecp;

#define fi first 
#define se second
#define pb push_back
#define ph push

const int INF=(ud)-1>>1;
const ll inf=(ull)-1ll>>1;

template<class T>void rd(T &a){
    a=0;char c;
    while(c=getchar(),!isdigit(c));
    do a=a*10+(c^48);
        while(c=getchar(),isdigit(c));
}
template<class T>void nt(T x){
    if(!x)return;
    nt(x/10);
    putchar(48+x%10);
}
template<class T>void pt(T x){
    if(!x)putchar('0');
    else nt(x);
}
template<class T>void Max(T &a,T b){
    if(a<b)a=b;
}
template<class T>void Min(T &a,T b){
    if(a==-1||a>b)a=b;
}
const int M=1e3+5;
bool mp[M][M];
inline void rdb(bool &b){
    static char c;
    for(;c=getchar(),!isdigit(c););
    b=c-'0';
}
struct Edge{
    int to,nxt;
}G[M*M];
int head[M],tot_edge;
inline void add_edge(int from,int to){
    G[tot_edge]=(Edge){to,head[from]};
    head[from]=tot_edge++;
}
int d[M],tid[M],n,k,w,que[M],A[M],B[M],C[M],dp[M];
bool mark[M];
inline bool Topology(bool f){
    int L=0,R=0;
    if(f)for(int i=1;i<=k;++i){
        if(!d[A[i]]){
            que[R++]=A[i];break;
        }
    }
    else for(int i=1;i<=w;++i){
        if(!d[B[i]]){
            que[R++]=B[i];break;
        }
    }
    for(;L<R;){
        int v=que[L++];
        tid[v]=L;
        for(int i=head[v];~i;i=G[i].nxt){
            int to=G[i].to;
            if(mark[to]^mark[v])continue;
            if((--d[to])==0)que[R++]=to;
        }
    }
    if(!f)return R==w;
    return R==k;
}
char str[M<<1];
inline void gao(){
    //Init
    memset(head,-1,sizeof(head));
    memset(d,0,sizeof(d));
    memset(tid,0,sizeof(tid));
    memset(mark,0,sizeof(mark));
    memset(dp,0,sizeof(dp));
    memset(C,0,sizeof(C));
    tot_edge=w=0;

    for(int i=1;i<=n;++i){
        gets(str);
        for(int j=1;j<=n;++j)
            mp[i][j]=str[j-1<<1]-'0';
    }
    for(int i=1;i<=k;++i)
        rd(A[i]),mark[A[i]]=1;
    for(int i=1;i<=n;++i)
        if(!mark[i])B[++w]=i;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
            if(mp[i][j]&&(mark[i]==mark[j]))
                add_edge(i,j),++d[j];
    bool flag=Topology(0);
    flag&=Topology(1);
    printf(flag?"YES ":"NO\n");
    if(!flag)return;
    w=0;
    for(int i=1;i<=n;++i){//tid表示拓扑序 
        if(mark[i])continue;
        int Mx=0,Mn=INF;
        for(int j=1;j<=k;++j)
            if(mp[A[j]][i])
                Max(Mx,tid[A[j]]);
        for(int j=1;j<=k;++j)
            if(mp[i][A[j]])
                Min(Mn,tid[A[j]]);
        if(Mn<Mx)mark[i]=1;
    }
    for(int i=1;i<=n;++i)
        if(!mark[i])B[++w]=i;
    for(int i=1;i<=w;++i)
        d[B[i]]=0;
    for(int i=1;i<=w;++i)
        for(int j=1;j<=w;++j)
            if(mp[B[i]][B[j]])++d[B[j]];
    Topology(0);
    for(int i=1;i<=w;++i){
        int Mx=0;
        for(int j=1;j<=k;++j)
            if(mp[A[j]][B[i]])Max(Mx,tid[A[j]]);
        C[tid[B[i]]]=Mx+1;
    }
    int ans=0;
    for(int i=1;i<=w;++i){
        int Mx=0;
        for(int j=1;j<i;++j)
            if(C[j]<=C[i])Max(Mx,dp[j]);
        dp[i]=Mx+1;
        Max(ans,dp[i]);
    }
    cout<<ans<<endl;
}
//#define LOCAL
int main(){
#ifdef LOCAL
    freopen("1003.in","r",stdin);
    freopen("ans.out","w",stdout);
#endif
    for(;scanf("%d %d\n",&n,&k),n;)gao();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值