HDU 3861 The King’s Problem 连通分量+二分匹配

题意:n个城市,m条有向边, 现在要把这个图分成块,对于块的定义:1,所有能够互通的点一定在一个块内。2,一个点可以到达另一个点,所经过的点只能是这个块内的。问做少要分多少个块?

想法:显然tarjan先缩点,然后可以想到,要想百分之一百满足第2个条件,那么每一个块最多只能有所点后的两个点,所以对所得的缩点进行二分匹配,然后求得最大独立集=col-(最大匹配数)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<vector>
using namespace std;
const int nodes=5000+5;
const int edges=100000+50;
int n,m;
struct node
{
    int v,next;
}e[edges];
vector<int>ve[nodes];
stack<int>s;
int head[nodes],cnt;
int link[nodes],vis[nodes];
int dfn[nodes],low[nodes],instack[nodes],paint[nodes];
int index,col;
void Init()
{
     memset(head,-1,sizeof(head));
     memset(dfn,0,sizeof(dfn));
     memset(low,0,sizeof(low));
     while(!s.empty()) s.pop();
     for(int i=1;i<=n;i++)
     ve[i].clear();
     memset(instack,0,sizeof(instack));
     memset(paint,0,sizeof(paint));
     index=col=1;
     cnt=0;
}
void add(int a,int b)
{
    e[cnt].v=b;
    e[cnt].next=head[a];
    head[a]=cnt++;
}
int Min(int a,int b)
{
    if(a<b) return a;
    return b;
}
void tarjan(int u)
{
    dfn[u]=low[u]=index++;
    instack[u]=1;
    s.push(u);
    for(int i=head[u];i+1;i=e[i].next)
    {
        int v=e[i].v;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=Min(low[u],low[v]);
        }
        else if(instack[v])
        {
            low[u]=Min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u])
    {
        int k=s.top();
        while(k!=u)
        {
            s.pop();
            instack[k]=0;
            paint[k]=col;
            k=s.top();
        }
        s.pop();
        instack[u]=0;
        paint[u]=col;
        col++;
    }
}
void tarjan_slove()
{
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i]) tarjan(i);
    }
    col--;
}
void build_map()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j+1;j=e[j].next)
        {
            int a=i,b=e[j].v;
            if(paint[a]!=paint[b])
            {
                ve[paint[a]].push_back(paint[b]);
            }
        }
    }
}
int dfs(int u)
{
    for(int i=0;i<ve[u].size();i++)
    {
        int v=ve[u][i];
        if(!vis[v])
        {
            vis[v]=1;
            if(link[v]==-1||dfs(link[v]))
            {
                link[v]=u;
                return 1;
            }
        }
    }
    return 0;
}
void slove()
{
    memset(link,-1,sizeof(link));
    int res=0;
    for(int i=1;i<=col;i++)
    {
        memset(vis,0,sizeof(vis));
        res+=dfs(i);
    }
    printf("%d\n",col-res);
}
int main()
{
    int test;
    scanf("%d",&test);
    while(test--)
    {
        scanf("%d%d",&n,&m);
        Init();
        for(int i=1;i<=m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            add(a,b);
        }
        tarjan_slove();
        build_map();
        slove();
    }
    return 0;
}
时间: 2024-11-05 04:48:48

HDU 3861 The King’s Problem 连通分量+二分匹配的相关文章

HDU 3861 The King’s Problem (强连通+二分匹配)

题目地址:HDU 3861 这题虽然是两个算法结合起来的.但是感觉挺没意思的..结合的一点也不自然,,硬生生的揉在了一块...(出题者不要喷我QAQ.) 不过这题让我发现了我的二分匹配已经好长时间没用过了..都快忘了..正好在省赛之前又复习了一下. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm>

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

The King's Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1637    Accepted Submission(s): 600 Problem Description In the Kingdom of Silence, the king has a new problem. There are N cit

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

HDU 3861 The King's Problem 题目链接 题意:给定一个有向图,求最少划分成几个部分满足下面条件 互相可达的点必须分到一个集合 一个对点(u, v)必须至少有u可达v或者v可达u 一个点只能分到一个集合 思路:先强连通缩点,然后二分图匹配求最小路径覆盖 代码: #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #include <

HDU 3861 The King&#39;s Problem(强连通分量缩点+最小路径覆盖)

http://acm.hdu.edu.cn/showproblem.php?pid=3861 题意: 国王要对n个城市进行规划,将这些城市分成若干个城市,强连通的城市必须处于一个州,另外一个州内的任意两个城市u,v,有从u到v的路径或从v到u的路径.求最少可以分成几个州. 思路: 这道题目挺好. 首先,强连通分量进行缩点,重新建图. 新建的图就是一个DAG图,接下来就转换成了最小路径覆盖问题. 最小路径覆盖就是用尽量少的不相交的简单路径覆盖DAG的所有顶点.每个顶点只属于一条路径,单个顶点也可以

HDU 3861.The King’s Problem 强联通分量+最小路径覆盖

The King’s Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 2947    Accepted Submission(s): 1049 Problem Description In the Kingdom of Silence, the king has a new problem. There are N cit

hdu 3861 The King’s Problem trajan缩点+二分图匹配

The King’s Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Problem Description In the Kingdom of Silence, the king has a new problem. There are N cities in the kingdom and there are M directional roads betw

HDU 3861 The King’s Problem 最小路径覆盖(强连通分量缩点+二分图最大匹配)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861 最小路径覆盖的一篇博客:https://blog.csdn.net/qq_39627843/article/details/82012572 题意: 把城市至少分成几个块,规则有三 1. A能B,B能到A,那么A,B一定要在一起. 2. 一个城市只能属于一个块. (说明了是最小不相交覆盖)3. 在一个块里的城市,任意2点之间必须有路径. 对于规则1,就是说强连通的必须在一起,所以用Tarjan

HDU 3861 The King’s Problem

题意:给我们一个图,问我们最少能把这个图分成几部分,使得每部分内的任意两点都能至少保证单向连通. 思路:使用tarjan算法求强连通分量然后进行缩点,形成一个新图,易知新图中的每个点内部的内部点都能保证双向连通,而新图中的点都是单向无环的,这个时候题目中要求的划分部分的条件,其实就是求最短路径覆盖(需要好好想一想),最短路径覆盖 = 结点个数 - 最大匹配值. 这个题我当时把j写成了i,就这么一个小地方,找了快20分钟,还死活发现不了..真是晕死了- #include<iostream> #i

HDU - 3861 The King’s Problem (强连通分量+最小路径覆盖)

思路:tarjarn缩点,然后剩下的就是纯粹的最小路径覆盖,最小路径覆盖=顶点数-匹配数.匹配数跑一遍匈牙利即可. 1 #include <iostream> 2 #include <queue> 3 #include <stack> 4 #include <cstdio> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <bitset