bzoj1143 [CTSC2008]祭祀river floyd+二分图匹配

Description


  在遥远的东方,有一个神秘的民族,自称Y族。他们世代居住在水面上,奉龙王为神。每逢重大庆典, Y族都
会在水面上举办盛大的祭祀活动。我们可以把Y族居住地水系看成一个由岔口和河道组成的网络。每条河道连接着
两个岔口,并且水在河道内按照一个固定的方向流动。显然,水系中不会有环流(下图描述一个环流的例子)。
这里写图片描述

  由于人数众多的原因,Y族的祭祀活动会在多个岔口上同时举行。出于对龙王的尊重,这些祭祀地点的选择必
须非常慎重。准确地说,Y族人认为,如果水流可以从一个祭祀点流到另外一个祭祀点,那么祭祀就会失去它神圣
的意义。族长希望在保持祭祀神圣性的基础上,选择尽可能多的祭祀的地点。

N≤100M≤1000

Solution


看一看题就知道要选出一些链使得这些链没有交
用floyd判连通性然后二分图匹配就可以了,可以想像成一开始有n个点,每连两个点就少一条边,最后答案是n-最大匹配

Code


#include <stdio.h>
#include <string.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

const int N=405;
const int E=80005;

struct edge {int x,y,next;} e[E];

int link[N],vis[N],ls[N],edCnt;

bool f[N][N];

void add_edge(int x,int y) {
    e[++edCnt]=(edge) {x,y,ls[x]}; ls[x]=edCnt;
}

void floyd(int n) {
    rep(k,1,n) rep(i,1,n) rep(j,1,n) {
        f[i][j]|=f[i][k]&f[k][j];
    }
}

bool find(int x,int id) {
    for (int i=ls[x];i;i=e[i].next) {
        if (vis[e[i].y]==id) continue;
        vis[e[i].y]=id;
        if (!link[e[i].y]||find(link[e[i].y],id)) {
            link[e[i].y]=x;
            return true;
        }
    }
    return false;
}

int main(void) {
    int n,m; scanf("%d%d",&n,&m);
    rep(i,1,m) {
        int x,y; scanf("%d%d",&x,&y);
        f[x][y]=1;
    }
    floyd(n);
    rep(i,1,n) rep(j,1,n) if (f[i][j]) add_edge(i,j);
    int ans=0;
    rep(i,1,n) ans+=find(i,i);
    printf("%d\n", n-ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/80736396