UVA1327 King‘s Quest 题解

本文解析了如何将强连通分量的概念运用到UVA1327问题中,通过王子与心仪女孩以及可娶女孩间的边建立,找出满足条件的共同连通分量。作者分享了代码实现细节,包括边的构建、使用前向星算法寻找连通分量并排序输出。
摘要由CSDN通过智能技术生成
笔者没 ac ,因为没绑定没提交。但在其他 OJ 上提交 ac 了,可以确保代码正确性。

UVA1327 King’s Quest 传送门

一道强连通分量的板子题。


思路:

最终可以满足条件的女孩 既要王子喜欢又可以被娶(也就是巫师那个名单) ,这不就类似强连通分量吗?只要王子喜欢的女孩和王子在同一个强连通分量里就都满足条件。

这道题和板子的区别主要在于建边和答案输出,主要说说这俩。

1. 建边:
  • 在王子到喜欢的女孩之间建边;

  • 在可以被娶女孩和王子之间建边。

这些结合题目及思路,不难理解。

2. 输出

概述:从王子喜欢的女孩中挑和王子在同一个强连通分量的女孩,保存起来,在按编号升序输出。

  1. 用前向星或 vector 找到和王子有直接连接的女孩(王子所喜欢的女孩);

  2. 判断两者是否在同一强连通分量中;

  3. 用变量记录女孩数量,用数组存下来女孩编号;

  4. 搜索完毕后,排序输出即可。


细节:

  1. 女孩的编号为保证不和王子重复,使第 i 个女孩的编号为 i + n ;

  2. 如需要要写上快读快写,某 OJ 用 cin 和 cout 也能过;

  3. 数据范围用 2000005 ,是越大越好


代码:

(这里把快读快写也附上了。)

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

const int maxn = 2000005;
int n;
int cnt, hd[maxn];
struct node{
   int to, nxt;
}e[maxn * 2];
int tmp, dfn[maxn], low[maxn];
int st[maxn], top;
int co[maxn], col;
int ans[maxn];

int read ()
{
   int x = 1, s = 0;
   char ch = getchar ();
   while (ch < '0' or ch > '9') {if (ch == '-') x = -1; ch = getchar ();}
   while (ch >= '0' and ch <= '9'){s = s * 10 + ch - '0'; ch = getchar ();}
   return x * s;
}

void write (int x)
{
   if (x == 0) return;
   write (x / 10);
   putchar (x % 10 + '0');
}

void add (int u, int v)
{
   e[++cnt].to = v;
   e[cnt].nxt = hd[u];
   hd[u] = cnt;
}

void tarjan (int u)
{
   dfn[u] = low[u] = ++tmp;
   st[++top] = u;
   for (int i = hd[u]; i; i = e[i].nxt)
   {
   	int v = e[i].to;
   	if (!dfn[v])
   	{
   		tarjan (v);
   		low[u] = min (low[u], low[v]);	
   	}	
   	else if (!co[v]) low[u] = min (low[u], dfn[v]);
   }	
   if (dfn[u] == low[u])
   {
   	col++;
   	co[u] = col;
   	while (st[top] != u)
   	{
   		co[st[top]] = col;
   		top--;
   	}
   	top--;
   }
}

int main ()
{
   cin >> n;
   for (int i = 1; i <= n; i++)
   {
   	int k;
   	cin >> k;
   	for (int j = 1; j <= k; j++)
   	{
   		int v;
   		cin >> v;
   		add (i, v + n);
   	}
   }
   for (int i = 1; i <= n; i++)
   {
   	int v;
   	cin >> v;
   	add (v + n, i);
   }
   for (int i = 1; i <= n; i++)
   {
   	if (!dfn[i]) tarjan (i);
   }
   for (int i = 1; i <= n; i++)
   {
   	int tot = 0;
   	for (int j = hd[i]; j; j = e[j].nxt)
   	{
   		int v = e[j].to;
   		if (co[i] == co[v]) 
   		{
   			tot++;
   			ans[tot] = v - n;	
   		}
   	}
   	cout << tot << " ";
   	sort (ans + 1, ans + tot + 1);
   	for (int l = 1; l <= tot; l++)
   	{
   		cout << ans[l] << " ";
   	} 
   	cout << endl;
   }
   return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值