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

来源:互联网 发布:坚持 知乎 编辑:程序博客网 时间:2024/05/22 02:20

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3861


题意:一个有向图,让你按规则划分区域,要求划分的区域数最少。1、有边u到v以及有边v到u,则u,v必须划分到同一个区域内。2、一个区域内的两点至少要有一方能到达另一方。3、一个点只能划分到一个区域内。


思路:肯定先强连通分量分解缩点,然后去求二分图的最小路径覆盖,最小路径覆盖:在图中找一些路径(路径数最少),使之覆盖了图中所有的顶点,且每个顶点有且仅和一条路径。最小路径覆盖 = 顶点数 - 最大匹配数


总结:用邻接矩阵记录缩点后的图去二分匹配,超时了,,,于是改成了vector实现的邻接表,就过了,,,

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>using namespace std;const int N = 5010;vector<int> g[N];struct edge{    int to, next;}G[N*20];int dfn[N], low[N], scc[N], st[N];int head[N], match[N];bool vis[N], used[N];int index, top, num, cnt;int n, m;void init(){    memset(head, -1, sizeof head);    memset(dfn, -1, sizeof dfn);    memset(vis, 0, sizeof vis);    index = cnt = top = num = 0;}void add_edge(int v, int u){    G[cnt].to = u;    G[cnt].next = head[v];    head[v] = cnt++;}void tarjan(int v){    dfn[v] = low[v] = index++;    st[top++] = v;    vis[v] = true;    int u;    for(int i = head[v]; i != -1; i = G[i].next)    {        u = G[i].to;        if(dfn[u] == -1)        {            tarjan(u);            low[v] = min(low[v], low[u]);        }        else if(vis[u])            low[v] = min(low[v], dfn[u]);    }    if(dfn[v] == low[v])    {        num++;        do        {            u = st[--top];            vis[u] = false;            scc[u] = num;        }while(u != v);    }}bool dfs(int v){    for(int i = 0; i < g[v].size(); i++)    {        int u = g[v][i];        if(used[u] == false)        {            used[u] = true;            if(match[u] == -1 || dfs(match[u]))            {                match[u] = v;                return true;            }        }    }    return false;}void slove(){    for(int i = 1; i <= n; i++)        if(dfn[i] == -1)            tarjan(i);    for(int i = 1; i <= num; i++)        g[i].clear();    for(int i = 1; i <= n; i++)        for(int j = head[i]; j != -1; j = G[j].next)            if(scc[i] != scc[G[j].to])                g[scc[i]].push_back(scc[G[j].to]);    int res = 0;    memset(match, -1, sizeof match);    for(int i = 1; i <= num; i++)    {        memset(used, 0, sizeof used);        if(dfs(i)) res++;    }    printf("%d\n", num - res);}int main(){    int t, a, b;    scanf("%d", &t);    while(t--)    {        init();        scanf("%d%d", &n, &m);        for(int i = 0; i < m; i++)        {            scanf("%d%d", &a, &b);            add_edge(a, b);        }        slove();    }    return 0;}


0 0
原创粉丝点击