标签: 最大独立集 最小路径覆盖
题目描述
In this problem, we would like to talk about unreachable sets of a directed acyclic graph G = (V, E). In mathematics a directed acyclic graph (DAG) is a directed graph with no directed cycles. That is a graph such that there is no way to start at any node and follow a consistently-directed sequence of edges in E that eventually loops back to the beginning again.
A node set denoted by V UR ⊂ V containing several nodes is known as an unreachable node set of G if, for each two different nodes u and v in V UR , there is no way to start at u and follow a consistently-directed sequence of edges in E that finally archives the node v. You are asked in this problem to calculate the size of the maximum unreachable node set of a given graph G.
输入
The input contains several test cases and the first line contains an integer T (1 ≤ T ≤ 500) which is the number of test cases.
For each case, the first line contains two integers n (1 ≤ n ≤ 100) and m (0 ≤ m ≤ n(n − 1)/2) indicating the number of nodes and the number of edges in the graph G. Each of the following m lines describes a directed edge with two integers u and v (1 ≤ u, v ≤ n and u != v) indicating an edge from the u-th node to the v-th node. All edges provided in this case are distinct.
We guarantee that all directed graphs given in input are DAGs and the sum of m in input is smaller than 500000.
输出
For each test case, output an integer in a line which is the size of the maximum unreachable node set of G.
样例输入
3
4 4
1 2
1 3
2 4
3 4
4 3
1 2
2 3
3 4
6 5
1 2
4 2
6 2
2 3
2 5
样例输出
2
1
3
题意
给定一个DAG,求出此图满足以下条件的最大点集合:集合中任意两点相互不可达。
思路
先求出DAG的闭包,然后闭包的最大独立集即为所求,DAG的闭包满足性质
- 然后我们可以把每个点拆分为两个点,分别代表一个点的出度和入读,那么会得到一个二分图。
- 假设初始我们用(n)个路径覆盖所有的点,之后二分图每增加一个匹配相当于把原DAG中的两个路径合并。所以(最小路径覆盖数=n-二分图最大匹配)
代码
// Ford-fulkerson算法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
const ll MOD=1e9+7;
const int maxn=100050;
const int inf=0x3f3f3f3f;
int n,m;
bool a[150][150];
struct Edge
{
int v,nxt,f,c;
}e[maxn];
int h[maxn],tot=1;
void addEdge(int x,int y,int w){
e[++tot]=(Edge){y,h[x],0,w};
h[x]=tot;
}
int s,t;
bool vis[250];
int dfs(int x,int flow){
if(vis[x]||flow==0) return 0;
vis[x]=true;
if(x==t){
return flow;
}
int ans=0;
for (int i = h[x]; i ; i=e[i].nxt)
{
int t=min(flow,e[i].c-e[i].f);
if(t>0&&(ans=dfs(e[i].v,t))){
e[i].f+=ans;
return ans;
}
t=min(flow,e[i^1].f);
if(t>0&&(ans=dfs(e[i].v,t))){
e[i^1].f-=ans;
return ans;
}
}
return 0;
}
int main(int argc, char const *argv[])
{
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n,&m);
memset(a,false,sizeof a);
memset(h,0,sizeof h);
for (int i = 0; i < m; ++i)
{
int x,y;
scanf("%d%d", &x,&y);
if(x>=1&&x<=n&&y>=1&&y<=n) a[x][y]=true;
}
tot=1;
for (int k = 1; k <= n; ++k)
{
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= n; ++j)
{
a[i][j]|=(a[i][k]&a[k][j]);
}
}
}
s=0,t=2*n+1;
for (int i = 1; i <= n; ++i)
{
addEdge(s,i,1);
addEdge(i,s,0);
addEdge(i+n,t,1);
addEdge(t,i+n,0);
for (int j = 1; j <= n; ++j)
{
if(a[i][j]){
addEdge(i,j+n,1);
addEdge(j+n,i,0);
}
}
}
int mat=0,flow=0;
memset(vis,false,sizeof vis);
while(flow=dfs(s,inf)){
mat+=flow;
memset(vis,false,sizeof vis);
}
printf("%d
", n-mat);
}
return 0;
}