[BZOJ1143][CTSC2008]祭祀river(floyed+二分图匹配)

题目描述

传送门

题解

用floyed判断连通性。连通的两个点就可以匹配,然后求二分图的最大匹配就可以了。
刚开始直接在原图求最小路径覆盖的思路是错误的,因为不能保证覆盖的路径之间不存在连通关系。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int max_n=105;
const int max_m=max_n*max_n;
const int max_e=max_m;
int n,m,x,y,ans;
int tot,point[max_n],v[max_m],nxt[max_m];
int belong[max_n],vis[max_n];
bool a[max_n][max_n];

inline void addedge(int x,int y)
{
    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
}
inline int find(int x,int k){
    for (int i=point[x]; i; i=nxt[i])
      if (vis[v[i]]!=k){
        vis[v[i]]=k;
        if (!belong[v[i]]||find(belong[v[i]],k)){
          belong[v[i]]=x;
          return true;
        }
      }
    return false;
}
inline void floyed()
{
    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];
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;++i)
    {
        scanf("%d%d",&x,&y);
        a[x][y]=true;
    }
    floyed();
    for (int i=1;i<=n;++i)
        for (int j=1;j<=n;++j)
            if (i!=j&&a[i][j])
                addedge(i,j);
    for (int i=1;i<=n;++i)
        if (find(i,i)) ans++;
    printf("%d\n",n-ans);
}

你可能感兴趣的:(二分图,CTSC,bzoj,floyed)