hdu3861The King’s Problem

原创 2013年12月03日 12:36:24

The King’s Problem

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1366    Accepted Submission(s): 507

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 between the cities. That means that if there is a road from u to v, you can only go from city u to city v, but can’t go from city v to city u. In order to rule his kingdom more effectively, the king want to divide his kingdom into several states, and each city must belong to exactly one state. What’s more, for each pair of city (u, v), if there is one way to go from u to v and go from v to u, (u, v) have to belong to a same state. And the king must insure that in each state we can ether go from u to v or go from v to u between every pair of cities (u, v) without passing any city which belongs to other state.
  Now the king asks for your help, he wants to know the least number of states he have to divide the kingdom into.
 
Input
The first line contains a single integer T, the number of test cases. And then followed T cases. 

The first line for each case contains two integers n, m(0 < n <= 5000,0 <= m <= 100000), the number of cities and roads in the kingdom. The next m lines each contains two integers u and v (1 <= u, v <= n), indicating that there is a road going from city u to city v.
 
Output
The output should contain T lines. For each test case you should just output an integer which is the least number of states the king have to divide into.
 
Sample Input
1 3 2 1 2 1 3
 
Sample Output
2
 
Source
 

 题目大意:1每个城市当且仅当属于一个state。2相互可达的两个城市要求必须属于一个state。3同一个state的两个城市u,v至少存在一条路径从u 到 v或在从v到u且不经过其他的state。求最小state的个数。
解体过程:刚开始练习图的连通性,我就读此题目,怎么也看不懂,然后就做其他强连通类的题目,回首再度才发现一句关键的话without passing any city which belongs to other state。因为图的二分匹配还没涉及到所有昨天看看匈牙利算法求二分匹配,估计到零点了就没在写,但思路已经很清晰了。
对原图缩点建DAG图,就是程序中的G2,然后用二分匹配求最大匹配(要明白DAG的最小路径覆盖和二分匹配的关系)。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <stack>
#define DEBUG 10
using namespace std;
const int maxn = 5000+10;
//Accepted	3861	140MS	1536K	2751 B	G++	Achiberx
int gn, gm;
vector<int> G[maxn]; // for original graph.
vector<int> G2[maxn];// for DAG.
// for dfs().
int dfs_clock, scc_cnt, sccno[maxn];
int pre[maxn], lowlink[maxn];
stack<int> S;
// for hungary();
int from[maxn], tot;
bool use[maxn];

void init() {
    for(int i = 0; i < maxn; i++) {
        G[i].clear(); G2[i].clear();
    }
}

void dfs(int u) {
    pre[u] = lowlink[u] = ++dfs_clock;
    S.push(u);
    for(int i = 0; i < (int)G[u].size(); i++) {
        int v = G[u][i];
        if(!pre[v]) {
            dfs(v);
            lowlink[u] = min(lowlink[u], lowlink[v]);
        } else if(!sccno[v]) {
            lowlink[u] = min(lowlink[u], pre[v]);
        }
    }
    if(pre[u] == lowlink[u]) {
        scc_cnt++;
        for(;;) {
            int x = S.top(); S.pop();
            sccno[x] = scc_cnt;
            if(x == u) break;
        }
    }
}

#ifndef DEBUG
void mid_res() {
    for(int i = 1; i <= gn; i++) {
        printf("sccno[%d] = %d\n", i, sccno[i]);
    }
}
#endif

void find_scc(int n) {
    dfs_clock = scc_cnt = 0;
    memset(pre, 0, sizeof(pre));
    memset(sccno, 0, sizeof(sccno));
    memset(lowlink, 0, sizeof(lowlink));
    for(int i = 1; i <= gn; i++) {
        if(!pre[i]) dfs(i);
    }
}

void build_map() {
    int u, v;
    for(int i = 1; i <= gn; i++) {
        for(int j = 0; j < (int)G[i].size(); j++) {
            u = sccno[i]; v = sccno[G[i][j]];
            if(u != v) {
                G2[u].push_back(v);
               // printf("%d -> %d\n", u, v);   // check if G2[] is correct.
            }
        }
    }
}

bool match(int x) {
    int v;
    for(int i = 0; i < (int)G2[x].size(); i++) {
        v = G2[x][i];
        if(!use[v]) {
            use[v] = true;
            if(from[v] == -1 || match(from[v])) {
                from[v] = x;
                return true;
            }
        }
    }
    return false;
}

int hungary() {
    tot = 0;
    memset(from, -1, sizeof(from));
    for(int i = 1; i <= scc_cnt; i++) {
        memset(use, 0, sizeof(use));
        if(match(i)) ++tot;
    }
    return tot;
}

int main()
{
    int T, u, v;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &gn, &gm);
        init();
        for(int i = 1; i <= gm; i++) {
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
        }
        find_scc(gn);
       // mid_res();
        build_map();
        int res = hungary();
        printf("%d\n", scc_cnt-res);
    }
    return 0;
}
版权声明:欢迎转载!

相关文章推荐

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

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

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

我们难道只有写暴力的水平么

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861 题意:有一个n个点m条边的有向图,把这个图分成几个区域,使得每个区域中的任意两点u, v要么u...

hdu3861The King’s Problem

题目意思就是一个国家有n个城市,里面的道路都是单向的,现在国王要把国家分割成区域,要求的就是,每个区域里面的点u、v,u到v可达或者是v到u可达。求最少要分隔成几个区域。 显然就是最小路径覆盖问题,...

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861 题意:一个国王掌管着n做城市,有m条有向道路,为了方便管理,国王要把这n个城市划分成尽可能少的...

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

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

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

题目地址:HDU 3861 这题虽然是两个算法结合起来的。但是感觉挺没意思的。。结合的一点也不自然,,硬生生的揉在了一块。。。(出题者不要喷我QAQ。) 不过这题让我发现了我的二分匹配已经好长时间...

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

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

hdu3861 The King’s Problem 强连通分量+二分图匹配

传送门 The King’s Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:hdu3861The King’s Problem
举报原因:
原因补充:

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