题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1143
这是我做的第一道CTSC的题,这题水得我都惊呆了。。。据说BZOJ只有第一问,没有问第二问,因为没数据,难怪这么水。。。
首先我们得知道二分图的独立集的概念:
二分图的独立集是二分图中一个任意两点都不相连的顶点的集合
二分图的最大独立集求法:
二分图的最大独立集=二分图点数-二分图最大匹配
然后这题就好做了。首先我们用Floyd求出相互可达的点的点对,然后用这些点对建立一个二分图,这个二分图中,有边相连的两个点都是相互可达的。然后我们求二分图的最大独立集即可。得到的二分图最大独立集中,任意两点之间均不可达。
注意边的个数要开n^2个!因为极限情况是任意两点之间均可达
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXV 110
#define MAXE 100100
using namespace std;
struct edge
{
int u,v,next;
}edges[MAXE];
int head[MAXV],nCount=0;
int dist[MAXV][MAXV],n,m;
int linky[MAXV];
bool visit[MAXV];
void AddEdge(int U,int V)
{
edges[++nCount].u=U;
edges[nCount].v=V;
edges[nCount].next=head[U];
head[U]=nCount;
}
bool dfs(int u)
{
for(int p=head[u];p!=-1;p=edges[p].next)
{
int v=edges[p].v;
if(visit[v]) continue;
visit[v]=true;
if(linky[v]==-1||dfs(linky[v]))
{
linky[v]=u;
return true;
}
}
return false;
}
int main()
{
memset(head,-1,sizeof(head));
memset(linky,-1,sizeof(linky));
scanf("%d%d",&n,&m);
int ans=n;
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
dist[x][y]=1;
}
for(int k=1;k<=n;k++) //Floyd预处理,求出u能到达v的点对(u,v);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dist[i][j]|=dist[i][k]&dist[k][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j)
if(dist[i][j])
AddEdge(i,j);
for(int i=1;i<=n;i++)
{
memset(visit,false,sizeof(visit));
if(dfs(i)) ans--;
}
printf("%d\n",ans);
return 0;
}