UVA1327 King‘s Quest

原题传送门

题目大意

n n n 个王子和 n n n 个女孩,每个王子可能喜欢多个女孩。先给出一个初始的完备匹配,问每个王子可以选择哪些女孩,即无论王子选择这些女孩中的哪一个,使得剩下的王子仍能够选择喜欢的女孩。

解题思路

比较裸的 Tarjan。

建图:

  • 连一条从王子到他喜欢的女孩的有向边。
  • 连一条巫师选的女孩和其对应的王子的有向边。

建完图后跑一边 Tarjan,在一个强连通分量里,王子可以和女孩随意搭配 (?

输出时统计与每个王子在同一个强连通分量的女孩的编号记录下来,然后按升序排序,最后输出。

注意数组要调到很大,因为每个王子所喜欢的女孩的个数最多为 n n n,所以数组至少要开到 n 2 n^2 n2 来记录。

王子的编号: 1 → n 1\to n 1n

女孩的编号: n + 1 → 2 n n+1 \to 2n n+12n

AC CODE

由于笔者快读太长,不方便放在这里,请读者自行加入快读。

#include <bits/stdc++.h>
using namespace std;

#define _ 20005

int n, m, cnt_node, cntn;
int ans[2000005];

int cnt;
array<int, 2000005> head;
struct abc
{
    int to, nxt;
};
array<abc, 2000005> dd;

array<bool, 2000005> vis;
array<int, 2000005> dfn, low, id;
stack<int> s;

inline void add(int u, int v)
{
    dd[++cnt].to = v;
    dd[cnt].nxt = head[u];
    head[u] = cnt;
}

inline void tarjan(int u)
{
    dfn[u] = low[u] = ++cnt_node;
    s.push(u);
    vis[u] = 1;
    for (int e = head[u]; e; e = dd[e].nxt)
    {
        if (!dfn[dd[e].to])
        {
            tarjan(dd[e].to);
            low[u] = min(low[dd[e].to], low[u]);
        }
        else if (vis[dd[e].to])
            low[u] = min(low[u], dfn[dd[e].to]);
    }
    if (low[u] == dfn[u])
    {
        cntn++;
        while (1)
        {
            int now = s.top();
            s.pop();
            vis[now] = 0;
            id[now] = cntn;
            if (now == u)
                break;
        }
    }
}

inline void init()
{
	cnt = 0;
	head.fill(0);
	
	dfn.fill(0);
	low.fill(0);
	vis.fill(0);
	id.fill(0);
	while(!s.empty()) s.pop();
}

signed main()
{
	while(scanf("%d", &n) != EOF)
	{
		init();
    	for(int i = 1; i <= n; ++i)
    	{
    		int k;
    		cin >> k;
    		for(int j = 1; j <= k; ++j)
    		{
    			int a;
    			cin >> a;
    			add(i, a + n);
			}
		}
		for(int i = 1; i <= n; ++i)
		{
			int a;
			cin >> a;
			add(a + n, i);
		}
		for(int i = 1; i <= n; ++i)
			if(!dfn[i]) tarjan(i);
		for(int i = 1; i <= n; ++i)
		{
			int res = 0;
			for(int j = head[i]; j; j = dd[j].nxt)
				if(dd[j].to > n && id[i] == id[dd[j].to]) ans[++res] = dd[j].to - n;
			sort(ans + 1, ans + res + 1);
			cout << res << " ";
			for(int k = 1; k <= res; ++k) cout << ans[k] << " ";
			cout << endl;
		}
	}
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值