HDU 3861 The King’s Problem

Posted icode-xiaohu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 3861 The King’s Problem相关的知识,希望对你有一定的参考价值。

  题意:给我们一个图,问我们最少能把这个图分成几部分,使得每部分内的任意两点都能至少保证单向连通。

  思路:使用tarjan算法求强连通分量然后进行缩点,形成一个新图,易知新图中的每个点内部的内部点都能保证双向连通,而新图中的点都是单向无环的,这个时候题目中要求的划分部分的条件,其实就是求最短路径覆盖(需要好好想一想),最短路径覆盖 = 结点个数 - 最大匹配值。

  这个题我当时把j写成了i,就这么一个小地方,找了快20分钟,还死活发现不了。。真是晕死了~

#include<iostream>
#include<cstdio>
#include<stack>
#include<cstring>
using namespace std;
#define maxn 5050
struct EDGE
{
    int to,nxt;
} edge[maxn*20];
EDGE newmap[maxn*20];
int head[maxn],low[maxn],dfn[maxn],id[maxn],newhead[maxn];
int vis[maxn],match[maxn];
int tot,sum,tot1;
stack <int> s;
void init()
{
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(id,0,sizeof(id));
    memset(head,-1,sizeof(head));
    memset(newhead,-1,sizeof(newhead));
    tot = 0,sum = 0;
    tot1 = 0;
    while(!s.empty()) s.pop();
}
void add_edge(int x,int y)
{
    newmap[tot1].to = y;
    newmap[tot1].nxt = newhead[x];
    newhead[x] = tot1++;
}
void tarjan(int u)
{
    s.push(u);
    dfn[u] = low[u] = ++tot;
    for(int i = head[u]; i != -1; i = edge[i].nxt)
    {
        int v = edge[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[u] = min(low[u],low[v]);
        }
        else if(!id[v])
        {
            low[u] = min(low[u],dfn[v]);
        }
    }
    if(low[u] == dfn[u])
    {
        sum++;
        while(!s.empty())
        {
            int num = s.top();
            s.pop();
            id[num] = sum;
            if(num == u) break;
        }
    }
    return;
}
bool Find(int u)
{
    for(int i = newhead[u]; i != -1;i = newmap[i].nxt)
    {
        int v = newmap[i].to;
        if(!vis[v])
        {
            vis[v] = 1;
            if(match[v] == -1 || Find(match[v]))
            {
                match[v] = u;
                return true;
            }
        }
    }
    return false;
}
int erfen()
{
   int ans = 0;
   memset(match,-1,sizeof(match));
   for(int i = 1;i <= sum;i++)
   {
       for(int j = 1;j <= sum;j++) vis[j] = 0;
       if(Find(i)) ans++;
   }
   return ans;
}
int main()
{
    int t,n,m,x,y;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        init();
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d",&x,&y);
            edge[i].to = y;
            edge[i].nxt = head[x];
            head[x] = i;
        }
        for(int i = 1;i <= n;i++)
        {
            if(!dfn[i])
            tarjan(i);
        }
        for(int i = 1;i <= n;i++)
        {
            int u = i;
            for(int j = head[u];j != -1;j = edge[j].nxt)
            {
                int v = edge[j].to;
                if(id[u] != id[v])
                {
                    add_edge(id[u],id[v]);
                }
            }
        }
        int ans = erfen();
        printf("%d\n",sum-ans);
    }
    return 0;
}

 

以上是关于HDU 3861 The King’s Problem的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

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

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

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