洛谷P4298 [CTSC2008]祭祀——题解

题目传送门
题目大意:
从一个图中选出最大的任意一点都无法到达其他点的点集。


思考过程&具体做法:
我们首先假设所有点都选了,现在问题转化为了删除最少的点。
我们从s向所有点连边,再从所有点的另一点向t连边,如果a能够达到b,我们从a向b的另一点连边,最终情况就是使得这个图从s无法到达t,即要求最小割。又因为这是一个只有两层的分层图,没必要写网络流,二分图匹配就可以解决了。


代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn=300;
struct stu
{
    int to,next;
}road[maxn*maxn]; int first[maxn*2];
int n,m,cnt;
int book[maxn*2],match[maxn*2],go[maxn][maxn];

void addedge(int x,int y)
{
    road[++cnt].to=y;
    road[cnt].next=first[x];
    first[x]=cnt;
}

bool dfs(int now)
{
    for(int i=first[now];i;i=road[i].next)
    {
        int to=road[i].to;
        if(!book[to])
        {
            book[to]=1;
            if(!match[to]||dfs(match[to]))
            {
                match[to]=now;
                return 1;
            }
        }
    }
    return 0;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        go[x][y]=1;
    }
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                go[i][j]=(go[i][j])|(go[i][k]&go[k][j]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(go[i][j]) addedge(i,j+n);
    cnt=0;
    for(int i=1;i<=n;i++)
    {
        memset(book,0,sizeof(book));
        if(dfs(i)) cnt++;
    }
    printf("%d\n",n-cnt);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39662197/article/details/80343604
今日推荐