其他分享
首页 > 其他分享> > hdu3861The King’s Problem(缩点+二分图匹配(匈牙利))

hdu3861The King’s Problem(缩点+二分图匹配(匈牙利))

作者:互联网

传送门

题目描述:

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.

题目大意:给咱们一个有向图,让我们划分,原图中在环内(强连通)的点必须分配到一起,可以按路径划分,一个点只出现在一条路径上,求把划分的数目最小

思路:环内的点必须在一个划分块中的话,那就先缩点,弄成无环图再说,然后就是最小路径覆盖裸题了,用的是匈牙利的二分图匹配,虽然没做过,但是抄了书上的模板居然oneA了,有点开心^_^

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100100;
typedef long long ll;
struct edge {
    int f, t, nxt;
}e[maxn << 1];
int hd[maxn], tot;
void add(int f, int t) {
    e[++tot] = { f,t,hd[f] };
    hd[f] = tot;
}
int n, m;
int low[maxn], dfn[maxn], cnt;
int stk[maxn], sk, instk[maxn];
int col[maxn], colnum;
int match[maxn], vis[maxn];
void init() {
    memset(match, 0, sizeof(match));
    memset(dfn, 0, sizeof(dfn));
    memset(col, 0, sizeof(col));
    memset(hd, 0, sizeof(hd));
    tot = cnt = colnum = 0;
}
void tarjan(int u) {//缩点模板
    low[u] = dfn[u] = ++cnt;
    stk[++sk] = u;
    instk[u] = 1;
    for (int i = hd[u]; i; i = e[i].nxt) {
        int v = e[i].t;
        if (!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if (instk[v]) {
            low[u] = min(low[u], dfn[v]);
        }
    }
    if (low[u] == dfn[u]) {
        colnum++;
        while (1) {
            int v = stk[sk--];
            instk[v] = 0;
            col[v] = colnum;
            if (v == u)break;
        }
    }
}
bool dfs(int u) {//匈牙利模板
    for (int i = hd[u]; i; i= e[i].nxt) {
        int v = e[i].t;
        if (vis[v])continue;//已经尝试过用V来匹配了,没有成功,就不要他了
        vis[v] = 1;
        if (!match[v] || dfs(match[v])) {
            //如果v还没有匹配的人选,或者让之前与v匹配的节点找其他点去匹配,如果成功了就让v与自己匹配
            match[v] = u;
            return true;
        }
    }
    return false;
}
int main() {
    //freopen("test.txt", "r", stdin);
    int t; scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &n, &m);
        init();
        for (int i = 1; i <= m;i++) {
            int a, b; scanf("%d%d", &a, &b);
            add(a, b);
        }
        for (int i = 1; i <= n; i++) {
            if (!dfn[i]) {
                tarjan(i);
            }
        }
        memset(hd, 0, sizeof(hd)); tot = 0;//将就之前的数组用,之前的图没必要存在了
        for (int i = 1; i <= m; i++) {//遍历所有边
            int u = e[i].f, v = e[i].t;
            if (col[u] != col[v]) {//把起始点不在同一连通分量的点重新连边
                add(col[u], col[v]);
            }
        }
        int sum = 0;
        for (int i = 1; i <= colnum; i++) {//二分图匹配
            memset(vis, 0, sizeof(vis));
            if (dfs(i))sum++;
        }
        printf("%d\n",colnum-sum);//原节点个数-匹配最大数目就是最小路径覆盖
    }
    return 0;
}

 

标签:缩点,King,city,go,state,each,kingdom,hdu3861The,king
来源: https://www.cnblogs.com/MYMYACMer/p/14613131.html