ICPC2017 Naning - The Maximum Unreachable Node Set

标签: 最大独立集 最小路径覆盖


题目描述

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", n-mat);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/sciorz/p/9021829.html