jzoj 5857. 【NOIP提高组模拟A组2018.9.8】没有上司的舞会 网络流

版权声明:2333 https://blog.csdn.net/liangzihao1/article/details/82528559

Description
“那么真的有果尔德施坦因这样一个人?”他问道。
“是啊,有这样一个人,他还活着。至于在哪里,我就不知道了。”
“那么那个密谋——那个组织?这是真的吗?不是秘密警察的捏造吧?”
“不是,这是真的。我们管它叫兄弟会。除了它确实存在,你们是它的会员以外,你们 就别想知道别的了。”

他知道的是,这种思想一定会一代一代地传下去,他们一定能够在没有黑暗的地方再会。

他不知道的是,兄弟会已经走到了崩溃的边缘;思想警察早已无孔不入;那没有黑暗的地方, 是友爱部,是 101 室……

兄弟会的头目之一,爱麦虞埃尔•果尔德施坦因,正在谋划着一场无力的反抗。这抗争的内容,竟是一场宏大的舞会。(这作为小资情调、腐朽没落的代表,以及未经允许的群众运动, 是大洋国严格禁止的(甚至是 crimethink))这也是为了加强组织的团结,并且为那终将到来的最后一战而激励、鼓舞士气。
众所周知,兄弟会为了避免思想警察的追捕,保密措施相当严密。会内一位高级干部奥勃良如此说:“从你们切身经验来说,你们永远连十来个会员也不认识。”(注意:测试数据可能不符合这句话)具体来说,每个人只认识他的全部上司。一个人的上司要么是他的直接上司
(在输入中会向你给出,并且可能不止一人),要么是这个人的某个上司的直接上司。为了增进同志之间的感情,同时为了防止渗入兄弟会的间谍破获整个组织的组成与结构,果尔德 施坦因想要确保在舞会中任意两个人都互不相识。
真理部的外围党员温斯顿在奥勃良的介绍下加入了兄弟会。他刚刚知道了这个激动人心的舞 会,仿佛又感受到了那若有若无的、来自旧时代的温暖。因为参与舞会的人越多,他与他亲爱的裘莉亚就越有可能重逢,所以他很好奇最多能有多少人参与。

Input
第一行两个正整数 N,M,表示兄弟会的会员人数以及关系数。然后 M 行,每行 2 个正整数 x,y(1<=x,y<=N,x≠y),表示 x 是 y 的直接上司(即 y 是 x 的直接下属)。

Output
输出一行一个整数,表示参加舞会的最多人数。

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

Sample Output
2

Data Constraint

对于 5%数据,满足 n<=5。
对于 20%数据,满足 n<=20。
对于另 10%数据,满足会员构成一棵外向树,即:除了一号会员(即果尔德施坦因本人)之外的每个会员,恰好只有一个上司,且一号会员没有上司。
对于另 10%数据,满足会员构成一颗内向树,即:除了一号会员(即温斯顿)之外的每个会员,恰好只有一个直接下属,且一号会员没有下属。
对于另 30%数据,满足每个会员要么没有上司,要么没有下属。

对于 100%数据,满足 n<=200,关系不会重复出现,且不会自相矛盾(即 A 既是 B 的上司也是 B 的下属)。换句话说,关系构成了一张无重边的有向无环图。保证图联通。

分析:
题目求的就是最长反链。
一开始我们相当于有 n 条链,每条链都可以取一个点,然后我们有一对匹配点就相当于连接两条链,这样选的点就少了1。答案就是n-最大匹配。不过要求出连通性,因为点可以重复走。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>

const int maxn=407;
const int maxe=3e5+7;
const int inf=0x3f3f3f3f;

using namespace std;

int n,m,s,t,cnt,x,y;
int a[maxn][maxn],dis[maxn],ls[maxn];

queue <int> q;

struct edge{
    int y,w,op,next;
}g[maxe];

void add(int x,int y,int w)
{
    g[++cnt]=(edge){y,w,cnt+1,ls[x]};
    ls[x]=cnt;
    g[++cnt]=(edge){x,0,cnt-1,ls[y]};
    ls[y]=cnt;
}

bool bfs()
{   
    for (int i=s;i<=t;i++) dis[i]=inf;
    q.push(s);
    dis[s]=0;  
    while (!q.empty())
    {
        int x=q.front();
        q.pop();
        for (int i=ls[x];i>0;i=g[i].next)
        {
            int y=g[i].y;
            if ((g[i].w) && (dis[y]>dis[x]+1))
            {
                dis[y]=dis[x]+1;
                q.push(y);
            }
        }
    }
    return (dis[t]!=inf);
}

int dfs(int x,int maxf)
{
    if ((x==t) || (!maxf)) return maxf;
    int ret=0;
    for (int i=ls[x];i>0;i=g[i].next)
    {
        int y=g[i].y;
        if ((g[i].w) && (dis[y]==dis[x]+1))
        {
            int f=dfs(y,min(maxf-ret,g[i].w));
            if (!f) dis[y]=-1;
            ret+=f;
            g[i].w-=f;
            g[g[i].op].w+=f;
        }
    }
    return ret;
}

int main()
{
    freopen("dance.in","r",stdin);
    freopen("dance.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        a[y][x]=1;
    }   
    for (int k=1;k<=n;k++)
    {
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=n;j++)
            {
                a[i][j]|=a[i][k]&a[k][j];
            }
        }
    }
    s=0,t=2*n+1;
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=n;j++)
        {
            if (a[i][j]) add(i,j+n,1);
        }
    }
    for (int i=1;i<=n;i++) add(s,i,1),add(i+n,t,1);
    int ans=n;  
    while (bfs()) 
       ans-=dfs(s,inf);
    printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/82528559