1904 King's Quest

King's Quest
Time Limit: 15000MS Memory Limit: 65536K
Total Submissions: 1045 Accepted: 329
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

 

Sample Output

 

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.

Source
Northeastern Europe  

***********************************************************************************

***********************************************************************************

  • Source Code
    /*
    题目给我们一个2*N个顶点的2分图,并且给了一个完美匹配(Perfect Matching)以及每个顶点可以连接的其他的顶点。
    题目要求是否可以确定某2个顶点连边后,其他2*(N - 1)个顶点的2分图是否可以构成完美匹配。
    分析:
    题目给了你一个初始的最大匹配 怎样用好这个匹配是非常关键的
    首先把图转化成有向图(因为后面我们要用到连通性判定)
    现在令王子为A集合,公主为B集合
    原图中所有的边转化成A->B的边 然后对原来的每一个匹配Ai->Bj 添加一条从Bj到Ai的边
    结论: 如果Ai,Bj能够互访 我们则认为Ai, Bj作为一条匹配边仍然不会影响其他王子和自己心爱的人匹配
    证明如下:
    现在有一个匹配Ai->Bj 我们知道Ai和Bj可以互访
    我们要验证其是否可以成立时对其他王子找MM没有影响
    1。如果题目中给的初始匹配包含这条边 则题目给出的初始匹配就证明了这位王子的公德心
    2。如果题目没有给出这条边 给出的是Ai -> Bk 由于Ai与Bk也可互访 所以存在Bj->Ai->Bk的增广路 也就是说可以建立另外一个匹配A?->Bk 
    所以同一个连通分量内部是可以换匹配的 呵呵
    
    关于求极大连通子图的方法 具体如下:
    求有向图的极大强连通分支 
    1.对图进行DFS遍历 遍历中记下所有的结束时间A[i].遍历的结果是构建的一座森林W1
      我们对W1中的每棵树G进行步骤2到步骤3的操作
    2.改变图G中每一条边的方向 构造出新的有向图Gr
    3.按照A[i]由小到大的顺序对Gr进行DFS遍历.遍历的结果是构建了新的树林W2.
      W2中每棵树上的顶点构成了有向图的极大强连通分支
    如果对DFS的相关算法不熟悉 请参考我的另一篇文章
    图的DFS信息构建+割点,桥,极大连通子图三大法宝
    
    */
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    const int N = 2010;
    int nv;
    vector<int> head[N], head2[N], S;
    int go[N], back[N]; 
    int scc[N];
    bool chk[N];
    bool love[N][N];
    
    void DFS(int x) {
        int i;
        chk[x] = 1;
        for(i = 0; i < head[x].size(); ++i) {
            int j = back[head[x][i]];
            if(!chk[j]) 
                DFS(j);    
        }
        S.push_back(x); //入栈
    }
    
     void DFS2(int x, int id) {
        int y = go[x], i;
        chk[y] = 1;
        scc[x] = id; //标记连通分支
        for(i = 0; i < head2[y].size(); ++i) {
            int j = go[head2[y][i]]; //找到对应的公主
            if(!chk[j])
                DFS2(head2[y][i], id);
        }
    }
    
     int main() {
        scanf("%d", &nv);
        int i, t, u, j;
        for(i = 0; i < nv; ++i) {
            scanf("%d", &t);
            while(t--) {
                scanf("%d", &u);
                love[i][u-1] = 1;
                head[i].push_back(u-1); //有向边
                head2[u-1].push_back(i); //逆转的有向边
            }
        }
        for(i = 0; i < nv; ++i) {
            scanf("%d", &t);
            go[i] = t-1;
           back[t-1] = i;
       }
    
        memset(chk, 0, sizeof(chk));
        for(i = 0; i < nv; ++i) if(!chk[i]) {
            DFS(i); //对王子作DFS 确定i到达的点
        }
    
        memset(chk, 0, sizeof(chk));
        int sccId = 0;
        for(i = S.size()-1; i >= 0; --i) {
            int j = S[i];
            if(!chk[go[j]]) {
                DFS2(j, sccId); 
     //再对公主做DFS 确定连通分支(对王子和对公主其实是一样的 写法有点不同而已:)
                sccId++;
            }
        }
    
        for(i = 0; i < nv; ++i) {
            vector<int> ans;
            for(j = 0; j < nv; ++j) if(love[i][j]) {
                if(scc[i] == scc[back[j]])
                    ans.push_back(j);
            }
            sort(ans.begin(), ans.end());
            printf("%d", ans.size());
           for(j = 0; j < ans.size(); ++j)
                printf(" %d", ans[j]+1);
            printf("/n");
       }
    
        return 0;
    }
  • 2 1 2
    2 1 2
    1 3
    1 4
    

    4
    2 1 2
    2 1 2
    2 2 3
    2 3 4
    1 2 3 4
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xcl119xxcl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值