POJ:1904-King's Quest

King’s Quest

Time limit15000 ms
Case time limit2000 ms
Memory limit65536 kB

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


解题心得:

  1. 题意就是有n个王子,n个姑娘,每个王子喜欢多个姑娘,巫师按照王子的意愿安排了一份最好的结婚名单,问你王子和哪些姑娘配对其他为王子都可以和自己喜欢的姑娘配对,都能得到最好的结婚名单。
  2. 刚开始读题读到一半以为是一个二分匹配问题,结果题目上直接给出了一个完美匹配,然后想了下,发现,一个国王能够生2000个儿子也是很牛皮的了,其实要王子选了姑娘其他王子也能选到自己喜欢的姑娘,那就是王子喜欢所有的姑娘,那么大家怎么选都是开心的了,能选到自己喜欢的。但是肯定不可能这么完美啊,但假如一个王子喜欢两个姑娘,他娶了其中一个姑娘,另一个王子也喜欢这两个姑娘,他娶了另一个姑娘,那他们换妻换到的也都是自己喜欢的姑娘。所以就可以按照这个关系建图,如果可以形成连通图那么大家可以随便交换姑娘(但是要注意交换的也要是自己喜欢的),但是肯定可以交换到在联通图中自己喜欢的姑娘。然后跑tarjan就可以了。
  3. 注意在一个联通图中的姑娘可能并不是都是自己喜欢的,还有就是要将姑娘的编号和王子的编号区分开,可以加一个2000以上的数给姑娘,这个题给了15S的时间,但是还是很容易超时,可以选择使用空间换时间的方法,直接用矩阵存关系。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<cstring>
using namespace std;
const int maxn = 6e3+100;
vector <int> ve[maxn],shrink[maxn],ans[maxn];//注意使用vector的清空的时候可以在使用完之后就立即清空节省时间
int low[maxn],dfn[maxn],n,num,tot;
bool vis[maxn],maps[maxn][maxn];
stack<int> st;

void init()//初始化
{
    while(!st.empty())
        st.pop();
    num = tot = 0;
    memset(vis,0,sizeof(vis));
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    memset(maps,0,sizeof(maps));
    for(int i=1; i<=n; i++)
    {
        int m;
        scanf("%d",&m);
        while(m--)
        {
            int to;
            scanf("%d",&to);
            to += 2020;
            maps[i][to] = true;
            ve[i].push_back(to);
        }
    }
    for(int i=1; i<=n; i++)
    {
        int to;
        scanf("%d",&to);
        to += 2020;
        ve[to].push_back(i);
    }
}

void tarjan(int x)//将按照关系建的图缩点
{
    dfn[x] = low[x] = ++tot;
    st.push(x);
    vis[x] = true;
    for(int i=0; i<ve[x].size(); i++)
    {
        int v = ve[x][i];
        if(!dfn[v])
        {
            tarjan(v);
            low[x] = min(low[x],low[v]);
        }
        else if(vis[v])
            low[x] = min(low[x],dfn[v]);
    }
    if(low[x] == dfn[x])
    {
        while(1)
        {
            int now = st.top();
            st.pop();
            vis[now] = false;
            shrink[num].push_back(now);
            if(now == x)
                break;
        }
        num++;
    }
}

void get_ans()
{
    vector <int> m,w;
    for(int i=0; i<num; i++)
    {
        m.clear();
        w.clear();
        for(int j=0; j<shrink[i].size(); j++)
        {
            int v = shrink[i][j];
            if(v <= 2000)
                m.push_back(v);
            else
                w.push_back(v);
        }
        sort(w.begin(),w.end());//要对姑娘排序,要求是按照升序输出
        for(int i=0;i<m.size();i++)
        {
            int u = m[i];
            for(int j=0;j<w.size();j++)
            {
                int v = w[j];
                if(maps[u][v])
                    ans[m[i]].push_back(w[j]);
            }
        }
        shrink[i].clear();
    }
    for(int i=1;i<=n;i++)
    {
        printf("%d ",ans[i].size());
        for(int j=0;j<ans[i].size();j++)
        {
            int v = ans[i][j];
            printf("%d ",v-2020);
        }
        ans[i].clear();
        ve[i].clear();
        printf("
");
    }
}

int main()
{
    while(scanf("%d",&n) != EOF)
    {
        init();
        for(int i=1; i<=n; i++)//跑tarjan缩点
            if(!dfn[i])
                tarjan(i);
        get_ans();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/GoldenFingers/p/9107210.html