UVA1327 King's Quest

原题传送门

题目大意

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

解题思路

比较裸的 Tarjan。

建图:

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

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

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

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

王子的编号:1n1\to n

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

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;
}
posted @   蒟蒻orz  阅读(2)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示