日常卖萌(1/1)

就要期中考试了QAQ
来看一道CTSC题:
这里写图片描述
首先题意是选择一些点使得这些点任意两点皆不可达。
即求最大反链长度。
在DAG中。
最大反链:
反链为一个点集P,对于在P集合任意的两个点u,v,满足u - > v == NULL && v - > u == NULL,则P集合元素个数就是反链长度。
最大反链长度当然就是最大的那个P集合。
最小链覆盖:
在图G中选择一些可相交的链,对所有链上的点取并集,如果能得到图G上的所有点,那么这些链组成了
有定理: 最大反链长度P= 最小链覆盖Q
证明一下:(应该是伪证QAQ)
if(P < Q):
则在所对应的最小链覆盖的那些链上每条链『与其它链不相交的部分』都放一个点,并把这条链标记,这P个点显然能构成反链,并且,Q个链覆盖上必然存在某些链没有被标记过的,证明这个反链集合不是最长反链。
if(P > Q):
根据抽屉原理,我们必然有一条链上被标记了>=2次,那么显然此时求得的最大反链不合法,因为这条链上的点是可达的。
所以P = Q。
然后我们就求一个最小链覆盖即可。
我们会求不相交的最小路径覆盖,那么怎么转化呢?
传(弗)递(洛)闭(伊)包(德)即可。
什么叫做传递闭包?
就是:在邻接矩阵中,先存有向图。
然后我们对于每个点求一下这个点能到达哪些点,更新下邻接矩阵即可。
我一开始想写BFS,然而感觉心虚,所以弗洛伊德即可。
w[i][j] = w[i][k] & w[k][j] | w[i][j];
然后这题感觉是个模板题,据说原题要输出方案,那就很恶心了。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#define Rep(i,n) for(int i = 1; i <= n ; i ++)
#define RepG(i,x) for(int i = head[x] ;~ i ; i = edge[i].next)
#define Rep_0(i,n) for(int i = 0 ; i < n ; i ++)
#define RD(i,x,n) for(int i = x; i <= n ; i ++)
#define CLR(a,b) memset(a,b,sizeof(a))
using namespace std;
const int inf = 1 << 30;
typedef long long ll;
int read(){
    char ch = getchar();
    while((ch < '0' || ch > '9') && ch != '-')ch = getchar ();
    int x = 0;
    bool flag = 0;
    if(ch == '-')ch = getchar(),flag = 1;
    while(ch >= '0' && ch <= '9')x = (x << 1) + (x << 3) + ch - '0',ch = getchar ();
    return flag ? -x : x;
}
const int N = 105;
int n,m,link[N];
bool vis[N],w[N][N];
bool dfs(int x){
    Rep(i,n)
        if(w[x][i] && !vis[i])
        {
            vis[i] = 1;
            if(link[i] == -1 || dfs(link[i]))
                return link[i] = x,1;
        }
    return 0;
}
void Floyd(){
    Rep(k,n)
        Rep(i,n)
            Rep(j,n)
                w[i][j] = (w[i][k] & w[k][j]) | w[i][j];
}
int main (){
    CLR(link,-1);
    n = read(),m = read();
    Rep(i,m)
    {
        int a = read(),b = read();
        w[a][b] = 1;
    }
    Floyd();
    int cnt = 0;
    Rep(i,n)
    {
        CLR(vis,0);
        if(dfs(i))cnt ++;
    }
    printf("%d\n",n - cnt);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值