poj 1904 King's Quest 【建模 求解SCC】

本文深入探讨了信息技术领域的多个关键概念与实践应用,包括但不限于前端开发、后端开发、移动开发、游戏开发、大数据开发、开发工具、嵌入式硬件、嵌入式电路知识、嵌入式开发环境等细分技术领域。通过分析这些领域的核心内容,旨在为读者提供全面而深入的技术知识,促进技术创新与应用实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

King's Quest
Time Limit: 15000MS Memory Limit: 65536K
Total Submissions: 8145 Accepted: 2955
Case Time Limit: 2000MS

Description

Once upon a time there lived a king and he had N sons. And there were N beautiful girls in the kingdom and the king knew about each of his sons which of those girls he did like. The sons of the king were young and light-headed, so it was possible for one son to like several girls. 

So the king asked his wizard to find for each of his sons the girl he liked, so that he could marry her. And the king's wizard did it -- for each son the girl that he could marry was chosen, so that he liked this girl and, of course, each beautiful girl had to marry only one of the king's sons. 

However, the king looked at the list and said: "I like the list you have made, but I am not completely satisfied. For each son I would like to know all the girls that he can marry. Of course, after he marries any of those girls, for each other son you must still be able to choose the girl he likes to marry." 

The problem the king wanted the wizard to solve had become too hard for him. You must save wizard's head by solving this problem. 

Input

The first line of the input contains N -- the number of king's sons (1 <= N <= 2000). Next N lines for each of king's sons contain the list of the girls he likes: first Ki -- the number of those girls, and then Ki different integer numbers, ranging from 1 to N denoting the girls. The sum of all Ki does not exceed 200000. 

The last line of the case contains the original list the wizard had made -- N different integer numbers: for each son the number of the girl he would marry in compliance with this list. It is guaranteed that the list is correct, that is, each son likes the girl he must marry according to this list. 

Output

Output N lines.For each king's son first print Li -- the number of different girls he likes and can marry so that after his marriage it is possible to marry each of the other king's sons. After that print Li different integer numbers denoting those girls, in ascending order.

Sample Input

4
2 1 2
2 1 2
2 2 3
2 3 4
1 2 3 4

Sample Output

2 1 2
2 1 2
1 3
1 4

Hint

This problem has huge input and output data,use scanf() and printf() instead of cin and cout to read data to avoid time limit exceed.


题意:有N个男孩和N个女孩。对每一个男孩,已经给出他所喜欢的女孩。现在给你一个满足完美匹配的婚配表,让你求出另一个表——在满足完美匹配的前提下,每个男孩可以与哪些女孩结婚。



把男孩i虚拟成节点i,女孩i虚拟成节i+N。我们用i - > i+N表示i喜欢i+N,用i+N->i表示 i与i+N结婚。

建图如下:

每个男孩向他喜欢的女孩建边,对于给出的完美匹配婚配表,每个女孩向她的男伴建边。

最后在图中跑一次tarjan。对男孩i所在的SCC,若有一个女孩节点j+N(j女孩)满足i -> j+N 则必然有i可以与j+N结婚。


AC代码:(注意要用数组标记男孩i和女孩j之间是否有边,若一个个查询会TLE)


#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#define MAXN 5000
#define MAXM 20000000
#define INF 0x3f3f3f3f
using namespace std;
struct Edge
{
    int from, to, next;
};
Edge edge[MAXM];
int head[MAXN], edgenum;
int low[MAXN], dfn[MAXN];
int sccno[MAXN], scc_cnt;
bool Instack[MAXN];
int dfs_clock;
stack<int> S;
vector<int> scc[MAXN];
int N;
void init()
{
    edgenum = 0;
    memset(head, -1, sizeof(head));
}
void addEdge(int u, int v)
{
    Edge E1 = {u, v, head[u]};
    edge[edgenum] = E1;
    head[u] = edgenum++;
}
int Map[2001][2001];
void getMap()
{
    init();
    int a;
    int num;
    memset(Map, 0, sizeof(Map));
    for(int i = 1; i <= N; i++)
    {
        scanf("%d", &num);
        while(num--)
        {
            scanf("%d", &a);
            addEdge(i, a+N);
            Map[i][a] = 1;
        }
    }
    for(int i = 1; i <= N; i++)
    {
        scanf("%d", &a);
        addEdge(a+N, i);
    }
}
void tarjan(int u, int fa)
{
    int v;
    low[u] = dfn[u] = ++dfs_clock;
    S.push(u);
    Instack[u] = true;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        v = edge[i].to;
        if(!dfn[v])
        {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
        }
        else if(Instack[v])
            low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u])
    {
        scc_cnt++;
        scc[scc_cnt].clear();
        for(;;)
        {
            v = S.top();S.pop();
            sccno[v] = scc_cnt;
            Instack[v] = false;
            scc[scc_cnt].push_back(v);
            if(u == v) break;
        }
    }
}
void find_cut(int l, int r)
{
    memset(low, 0, sizeof(low));
    memset(dfn, 0, sizeof(dfn));
    memset(Instack, false, sizeof(Instack));
    memset(sccno, 0, sizeof(sccno));
    dfs_clock = scc_cnt = 0;
    for(int i = l; i <= r; i++)
        if(!dfn[i]) tarjan(i, -1);
}
int rec[MAXN];//记录可婚配的女孩编号
void solve()
{
    find_cut(1, 2*N);
    for(int i = 1; i <= N; i++)
    {
        int u = sccno[i];//男孩所在的SCC
        int sum = 0;//统计数目
        for(int j = 0; j < scc[u].size(); j++)
        {
            if(scc[u][j] > N && Map[i][scc[u][j]-N])//在一个强连通分量 且有边相连
                rec[sum++] = scc[u][j] - N;//记录编号
        }
        printf("%d", sum);
        sort(rec, rec+sum);
        for(int j = 0; j < sum; j++)
            printf(" %d", rec[j]);
        printf("\n");
    }
}
int main()
{
    while(scanf("%d", &N) != EOF)
    {
        getMap();
        solve();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值