题目传送门
题目大意:
从一个图中选出最大的任意一点都无法到达其他点的点集。
思考过程&具体做法:
我们首先假设所有点都选了,现在问题转化为了删除最少的点。
我们从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;
}