zoukankan      html  css  js  c++  java
  • ICPC2017 Naning

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


    题目描述

    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;
    }
    
  • 相关阅读:
    (2.3)备份与还原--事务的运行模式与处理机制
    (2.2)备份与还原--备份类型与恢复模式、备份介质
    (2.1)备份与还原--sql server文件的概念及操作
    (1.3.3)权限控制
    (1.3.2)登录验证(加密连接与登录验证)
    (1.3.1)连接安全(连接实例与网络协议及TDS端点)
    static class
    cnblog
    microsoft
    C# socket android
  • 原文地址:https://www.cnblogs.com/sciorz/p/9021829.html
Copyright © 2011-2022 走看看