[HDU 3861] The King's Problem (最小路径覆盖)

原创 2016年05月31日 19:34:38

HDU - 3861

将图分成若干块,满足
1. 相互联通的两个点必须在同一块
2. 同一块中的任意两点,必须能单向可达


首先先用Tarjan缩点,
然后同一块的实际上必须在一条单向的路径上
然后问题就转化为了dag上不相交的最小路径覆盖

这个问题可以转化为二分图匹配解决
建立一个二分图,原图中任意一个点 u
在二分图中都拆成两个点,X部的u点和 Y部的 u’点
原图中的任意一条边 u->v在二分图中连上 u->v’
然后原图的总点数,减去二分图的最大匹配,即为最小路径覆盖

证明如下:

对于二分图 X部的一个点 u,如果他在 Y部有一个匹配 v’
那么对于原图,则代表了选定这条边 u->v,代表 u点在原图有后继
而没有匹配的点,即没有后继的点都是某条路径的终点,
所以原图中的路径数等于 X部中没有匹配的点数
当二分图最大匹配的时候,没有后继的点数最少
此时就产生了最小路径覆盖

#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef pair<int,int> Pii;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DBL;
typedef long double LDBL;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Sqr(a) (a*a)

const int maxn=5e3+10, maxm=1e5+10;
struct Graph
{
    int V,E;
    int edn, *last;
    int *u, *v, *nxt;
    Graph(int a, int b):V(a),E(b)
    {
        last=new int[V];
        u=new int[E]; v=new int[E]; nxt=new int[E];
        init();
    }
    ~Graph(){delete []last;delete []u;delete []v;delete []nxt;}
    void init(){edn=0; memset(last,-1,sizeof(int)*V);}
    void adde(int tu, int tv)
    {
        u[edn] = tu;
        v[edn] = tv;
        nxt[edn] = last[tu];
        last[tu] = edn++;
    }
    void pri(){for(int i=0; i<edn; i++) printf("%d->%d\n", u[i], v[i]);}
};

struct Tarjan
{
    Graph &G;
    int dfst, dfsn[maxn], low[maxn];
    int scnt, scc[maxn];
    int skt, stak[maxn];
    bool ins[maxn];
    Tarjan(Graph &a):G(a){};
    int SCC(int);
    int dfs(int);
};

struct Hungarian
{
    Graph &G;
    int res, match[2*maxn];
    bool ins[2*maxn];
    Hungarian(Graph &a):G(a){};
    int solve(int);
    int dfs(int);
};

int N,M;
Graph graph(maxn,maxm), div_g(2*maxn,maxm);
Tarjan tarjan(graph);
Hungarian hug(div_g);

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
    #endif

    int T;
    scanf("%d", &T);
    for(int ck=1; ck<=T; ck++)
    {
        graph.init();
        div_g.init();
        scanf("%d%d", &N, &M);
        for(int i=0; i<M; i++)
        {
            int u,v;
            scanf("%d%d", &u, &v);
            graph.adde(u,v);
        }
        N = tarjan.SCC(N);
        for(int i=0; i<graph.edn; i++)
        {
            int u=graph.u[i], v=graph.v[i];
            div_g.adde(u,v+N);
        }
//      div_g.pri();
        int mcnt = hug.solve(2*N);
        printf("%d\n", N-mcnt);
    }
    return 0;
}

int Tarjan::SCC(int n)
{
    dfst=0; CLR(dfsn); CLR(low);
    scnt=0; CLR(scc);
    skt=0; CLR(ins);

    for(int i=1; i<=n; i++) if(!dfsn[i]) dfs(i);

    int tot=G.edn;
    G.init();
    for(int e=0; e<tot; e++)
    {
        int u=G.u[e], v=G.v[e];
        if(scc[u] == scc[v]) continue;
        G.adde(scc[u],scc[v]);
    }
    return scnt;
}

int Tarjan::dfs(int u)
{
    dfsn[u] = low[u] = ++dfst;
    stak[++skt] = u;
    ins[u] = 1;

    for(int e=G.last[u]; ~e; e=G.nxt[e])
    {
        int v = G.v[e];
        if(!dfsn[v])
        {
            dfs(v);
            low[u] = min(low[u], low[v]);
        }
        else if(ins[v]) low[u] = min(low[u], low[v]);
    }

    if(low[u] == dfsn[u])
    {
        scnt++;
        while(skt)
        {
            ins[ stak[skt] ] = 0;
            scc[ stak[skt] ] = scnt;
            skt--;
            if(stak[skt+1] == u) break;
        }
    }

    return 0;
}

int Hungarian::solve(int n)
{
    res=0;
    CLR(match);
    for(int i=1; i<=n; i++)
    {
        if(!match[i])
        {
            CLR(ins);
            if(dfs(i)) res++;
        }
    }
    return res;
}

int Hungarian::dfs(int u)
{
    for(int e=G.last[u]; ~e; e=G.nxt[e])
    {
        int v=G.v[e];
        if(ins[v]) continue;
        ins[v]=1;
        if(!match[v] || dfs(match[v]))
        {
            match[v]=u;
            match[u]=v;
            return 1;
        }
    }
    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

The King’s Problem (hdu 3861 强连通缩点+最小路径覆盖)

题意:n个城市m条有向边,把这些城市分成若干个州,分的原则是(1)u和v可以互相到达的话他们两个必须在同一个州(2)同一个州里任意两个城市u和v要满足u可以到达v或者v可以到达u。问州的最小个数是多少...

HDU3861 The King’s Problem Tarjan缩点+二分图求最小路径覆盖

这题一开始理解有问题。 对于每一个洲,如果洲里面的任意两个城市u,v,如果u有路径到v,则v也要有路径到u。不要求两两城市都存在路径。 用Tarjan求强连通分量缩点,在用二分图求 #i...
  • neofung
  • neofung
  • 2012年01月11日 19:35
  • 712

hdu3861 The King’s Problem (强连通+最小路径覆盖)

题意:题目的意思很清晰,对于一个有向图,将N个点划分成最少的集合个数,同时满足俩个条件: 首先,最小路径覆盖=总节点数-最大匹配数。这个应该已经是路人皆知了。 所谓最小路径覆盖,是...

HDU 3861 The King’s Problem(强连通缩点 + 最小路径覆盖)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861 题意:给出一张N个点M条边的有向图,要求划分出的区域最少,划分规则满足: 1.(...

hdu 3861 The King’s Problem(缩点+最小路径覆盖)

The King’s Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe...
  • WEYuLi
  • WEYuLi
  • 2013年08月04日 22:57
  • 687

HDU3861-The King’s Problem(有向图强连通缩点+最小路径覆盖)

题目链接 题意:题目大意:一个有向图,让你按规则划分区域,要求划分的区域数最少。  规则如下:  1、有边u到v以及有边v到u,则u,v必须划分到同一个区域内。  2、一个区域...

HDU 3861 The King’s Problem 强连通分量分解 + 二分图最小路径覆盖

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3861 题意:一个有向图,让你按规则划分区域,要求划分的区域数最少。1、有边u到v以及有边v到u,...

hdu3861 The King’s Problem (强连通缩点+最小路径覆盖)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3861 /*题解: state划分规则:至少存在一条路径可以从city u到city v, 也存在一...

hdu3861The King’s Problem (强连通 缩点+最小路径覆盖)

The King’s Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)...

hdu3861 The King’s Problem【强连通+最小路径覆盖】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861 题意:一个国王掌管着n做城市,有m条有向道路,为了方便管理,国王要把这n个城市划分成尽可能少的...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[HDU 3861] The King's Problem (最小路径覆盖)
举报原因:
原因补充:

(最多只允许输入30个字)