POJ 1904 King's Quest(强连通图)题解

题意:n个王子有自己喜欢的ki个公主,有n个公主,每个王子只能娶一个自己喜欢的公主且不能绿别的王子。现在给你一种王子娶公主的方案,并且保证这种方案是正确的。请你给出,每个王子能娶哪些公主,要求娶这些公主时,其他王子也能娶到公主。

思路:还以为是完全匹配,直接暴力匹配显然TLE了。正解是缩点...我们把每个王子指向自己喜欢的公主们,然后把给定的方案中的公主指向自己嫁给的王子,然后缩点,同一个点中王子喜欢的公主都能娶。因为每个王子指向的肯定都是公主(至少两个),公主指向的肯定都是王子,所以想要形成一个强连通图这个图中王子公主数量肯定是相同的,那么假如王子选择一个自己喜欢的公主,那么这个图中的其他的王子可以选择其他的公主,显然肯定能完全匹配。

代码:

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn = 4000 + 10;
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int head[maxn], ans[maxn], tot;
struct Edge{
    int to, next;
}edge[maxn * maxn];
int low[maxn], dfn[maxn], Stack[maxn], belong[maxn];
int index, top, scc;
bool instack[maxn];
void addEdge(int u, int v){
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void tarjan(int u){
    int v;
    low[u] = dfn[u] = ++index;
    Stack[top++] = u;
    instack[u] = true;
    for(int i = head[u]; i != -1; i = edge[i].next){
        v = edge[i].to;
        if(!dfn[v]){
            tarjan(v);
            if(low[u] > low[v]) low[u] = low[v];
        }
        else if(instack[v] && low[u] > dfn[v]){
            low[u] = dfn[v];
        }
    }
    if(low[u] == dfn[u]){
        scc++;
        do{
            v = Stack[--top];
            instack[v] = false;
            belong[v] = scc;
        }while(v != u);
    }
}
void solve(int n){
    memset(dfn, 0, sizeof(dfn));
    memset(instack, false, sizeof(instack));
    index = scc = top = 0;
    for(int i = 1; i <= n; i++){
        if(!dfn[i])
            tarjan(i);
    }
}
void init(){
    tot = 0;
    memset(head, -1, sizeof(head));
}
int main(){
    int n;
    while(~scanf("%d", &n)){
        int k, tmp;
        init();
        for(int i = 1; i <= n; i++){
            scanf("%d", &k);
            while(k--){
                scanf("%d", &tmp);
                addEdge(i, tmp + n);
            }
        }
        for(int i = 1; i <= n; i++){
            scanf("%d", &tmp);
            addEdge(tmp + n, i);
        }
        solve(2 * n);
        int ret;
        for(int u = 1; u <= n; u++){
            ret = 0;
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(belong[v] == belong[u]){
                    ans[ret++] = v - n;
                }
            }
            sort(ans, ans + ret);
            printf("%d", ret);
            for(int i = 0; i < ret; i++){
                printf(" %d", ans[i]);
            }
            printf("\n");
        }
    }
    return 0;
}

 

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


下一篇:HDU - 5201 :The Monkey King (组合数 & 容斥)