bzoj1143: [CTSC2008]祭祀river
这个题,看题解后思路就感觉比较简单了。。。。。。还是说一下吧
首先要求的是一共有几个不会互相连通的点
在有向无环图中,有如下的一些定义和性质:
链:一条链是一些点的集合,链上任意两个点x, y,满足要么 x 能到达 y ,要么 y 能到达 x 。
反链:一条反链是一些点的集合,链上任意两个点x, y,满足 x 不能到达 y,且 y 也不能到达 x。
大概就是求最长反链了
一个定理:最长反链长度 = 最小链覆盖(用最少的链覆盖所有顶点)这是显然的。
然后我们不能仅仅只用它给的边来跑最小链覆盖,因为我们的边还不全,于是我们要把每个能到达的两个点建边,然后就是最小链覆盖
最小链覆盖:详见网络流24题,转化为二分图。
用什么跑二分图就随意了,匈牙利,网络流都可以
ps:bzoj上的题全,所以只做了30%的
/**************************************************************
Problem: 1143
User: tym983398371
Language: C++
Result: Accepted
Time:32 ms
Memory:1316 kb
****************************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,map[105][105],vis[105],f[105];
bool find(int x)
{
for (int i=1;i<=n;i++)
{
if (map[x][i]&&!vis[i])
{
vis[i]=1;
if (!f[i]||find(f[i]))
{
f[i]=x;
return 1;
}
}
}
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
int x,y,ans=0;
memset(f,0,sizeof(f));
memset(map,0,sizeof(map));
for (int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
map[x][y]=1;
}
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (map[i][k]&&map[k][j]) map[i][j]=1;
ans=n;
for (int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if (find(i)) ans--;
}
printf("%d\n",ans);
return 0;
}