题意:
给你n个点, m条边 , 然后让你集合A中的点集。(就是最多选多少边,使得集合内地点都不可达)
这道题emmm。。。现学现卖过的。。。。果然菜的无可救药。。。
这道题算法是 Flora + 二分图的最小顶点覆盖(二分图算法)
先用fiora求出可达矩阵(就是 如果 mpt[i][j] == mpt[j][k] 那么 mpt[i][k] 就是可以通达的)
然后我们可以通过这个图在找出它的最大匹配。
原贴参考链接:
链接1(匈牙利匹配算法)
链接二(题解)
在贴几个结论:
3个重要结论:
最大匹配数:最大匹配的匹配边的数目
最小点覆盖数:选取最少的点,使任意一条边至少有一个端点被选择
最大独立集:选取最多的点,使任意所选两点均不相连
最小路径覆盖数:对于一个 DAG(有向无环图),选取最少条路径,使得每个顶点属于且仅属于一条路径。路径长可以为 0(即单个点)。
最小点覆盖数=最大匹配数
最小路径覆盖 =顶点数-最大匹配数
二分图最大独立集 = 顶点数 - 最大匹配数
注意:
在有向图中,一个点可以反复使用(有限制), 例如:
4个点 , 3 条边
1 3
2 3
3 4
他的最大匹配为二;
其匹配结果如下:
2 3 , 3 4 ;
下面是代码:
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std ;
const int maxn = 105 ;
int mpt[maxn][maxn] ;
int vis[maxn] ;
int link[maxn] ;
int n , m ;
#define INF 0x3f3f3f3f
void f(){
for(int k = 1 ; k <= n ; k++)
for(int i = 1 ; i<= n ; i++)
for(int j = 1 ; j <= n ; j++)
if(mpt[i][k]&&mpt[k][j])
mpt[i][j]=1;
}
int dfs(int num)
{
for(int i=1;i<=n;i++)
{
if(mpt[num][i]&& !vis[i])
{
vis[i]=1;
if(link[i]==-1||dfs(link[i]))
{
link[i] = num;
return 1;
}
}
}
return 0;
}
int main(){
int t ;
cin >> t ;
while(t--)
{
scanf("%d %d",&n,&m);
int ans = 0 ;
int u , v , w ;
memset(mpt , 0 , sizeof(mpt)) ;
memset(link , -1 , sizeof(link)) ;
for(int i = 1 ; i <= m ; i++)
{ cin >> u >> w ;
mpt[u][w] = 1 ;
}
f();
for(int i=1;i<=n;i++)
{
memset(vis , 0 , sizeof(vis)) ;
if(dfs(i))
ans++;
}
printf("%d\n",n-ans);
}
return 0 ;
}