题目链接: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; }