POJ 1904:King's Quest【tarjan】

题目大意:给出一个二分图的完美匹配(王子和公主的烧死名单表),二分图x部和y部均只有n个点,问对于每一个x部的点,他能选择哪些点与之匹配 使得与之匹配后,剩余图的最大匹配仍然是n

思路:这题是大白书379页二分图的压轴题,在图论刷的题还不多时思考过这题,现在想来也不难想

这题引人瞩目的一点便是预先给出了一个二分图的初始匹配

对每个点枚举后增广显然不怎么可行,那么还是图论问题的经典思考方式,点和边各表示什么

题目的输入天然的给出了一个图,但对这题好像没什么用处,于是开始思考把给出的初始匹配的每条边看成一个点!!!

那样构成的图每个点就是一个王子和一个公主的配对,如果一个王子还可以花心爱上除了初始匹配的公主外的其他公主,那么从这个点向那个公主处连一条边

然后显然新构成的图中如果有环,(A到B,B又可以到A),那么我们就可以把原来二分图中的匹配顺次沿一格(形象一点就是环中的王子们顺次把自己初始匹配的姑娘送给下一个王子),这样肯定不改变二分图的最大匹配数

然后联想到在一个强连通分量里面,任意两点间肯定是有环的,因此可以缩点,一个SCC里的姑娘肯定可以取到的,不在一个SCC里的姑娘由于是DAG 所以不可能存在环,因此无论如何也取不到

然后就A了,输出的时候得递增 因此贡献了发WA

#include<cstdio>

#include<string.h>

#include<iostream>

#include<algorithm>

#define maxn 600090

using namespace std;

int head[maxn],next[maxn],point[maxn],now=0;

int stack[maxn],top,col,dfn[maxn],low[maxn];

int tim,belong[maxn],x[maxn],y[maxn];

int match[maxn],ans[maxn],h=0,idx=0;

bool instack[maxn];

void add(int x,int y)

{

next[++now]=head[x];

head[x]=now;

point[now]=y;

}

void tarjan(int k)

{

stack[++top]=k;

dfn[k]=low[k]=++tim;

instack[k]=1;

for(int i=head[k];i;i=next[i])

{

int u=point[i];

if(dfn[u]==0)

{

tarjan(u);

low[k]=min(low[k],low[u]);

}

else if(instack[u]==1)

{

low[k]=min(low[k],low[u]);

}

}

if(dfn[k]==low[k])

{

col++;

int u;

do

{

u=stack[top--];

belong[u]=col;

instack[u]=0;

}while(u!=k);

}

}

int main()

{

int n,k,tt;

scanf("%d",&n);

for(int i=1;i<=n;i++)

{

scanf("%d",&k);

for(int j=1;j<=k;j++)

{

scanf("%d",&tt);

x[++h]=i;y[h]=tt;

}

}

for(int i=1;i<=n;i++)

{

scanf("%d",&tt);

match[tt]=i;

}

for(int i=1;i<=h;i++)

{

if(match[y[i]]!=x[i])

{

add(x[i],match[y[i]]);

}

}

for(int i=1;i<=n;i++)if(dfn[i]==0)tarjan(i);

for(int i=1;i<=n;i++)

{

int hh=0;

while(x[idx+1]==i && idx+1<=h)

{

idx++;

if(belong[i]==belong[match[y[idx]]])

ans[++hh]=y[idx];

}

printf("%d",hh);

sort(ans+1,ans+1+hh);

for(int i=1;i<=hh;i++)

{

printf(" %d",ans[i]);

}

printf("\n");

}

return 0;

}

POJ 1904:King's Quest【tarjan】

时间: 2024-10-29 19:06:58

POJ 1904:King's Quest【tarjan】的相关文章

从程序员到项目经理(26):项目管理不能浑水摸鱼【转载】

怎样才算是一名合格的项目经理?最根本的一点,就是要胸有成竹,否则管项目就好比浑水摸鱼,最后的结果就是得到一只死鱼! 成功的项目经理都有一个共同的特征,那就是胸有成竹.如果做不到这一点,意味着项目经理缺乏总体的盘算,只能走一步看一步,项目究竟会走多少弯路,那就只能看运气了. 1.胸有成竹是项目经理胜任的标志 顾名思义,胸有成竹就是说一个画家,在画竹子之前,心里就有了竹子的形象,画家所做的,只不过是把心里所想的东西,誊到纸面上而已,当然可以做到驾轻就熟.游刃有余了. 胸有成竹是对一个优秀画家的要求,

剑指Offer:对称的二叉树【28】

剑指Offer:对称的二叉树[28] 题目描述 请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的. 题目分析 Java题解 /* public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } } */ public class Solution {

LeetCode:有效的括号【20】

LeetCode:有效的括号[20] 题目描述 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合. 左括号必须以正确的顺序闭合. 注意空字符串可被认为是有效字符串. 示例 1: 输入: "()" 输出: true 示例 2: 输入: "()[]{}" 输出: true 示例 3: 输入: "(]" 输出: false 示例 4: 输入: "

LeetCode:划分字母区间【763】

LeetCode:划分字母区间[763] 题目描述 字符串 S 由小写字母组成.我们要把这个字符串划分为尽可能多的片段,同一个字母只会出现在其中的一个片段.返回一个表示每个字符串片段的长度的列表. 示例 1: 输入: S = "ababcbacadefegdehijhklij" 输出: [9,7,8] 解释: 划分结果为 "ababcbaca", "defegde", "hijhklij". 每个字母最多出现在一个片段中. 像

LeetCode:存在重复元素【217】

LeetCode:存在重复元素[217] 题目描述 给定一个整数数组,判断是否存在重复元素. 如果任何值在数组中出现至少两次,函数返回 true.如果数组中每个元素都不相同,则返回 false. 示例 1: 输入: [1,2,3,1] 输出: true 示例 2: 输入: [1,2,3,4] 输出: false 示例 3: 输入: [1,1,1,3,3,4,3,2,4,2] 输出: true 题目分析 对于数据结构HashSet, 我们首先需要知道的是HashSet是不包含重复元素的,其次是存储

LeetCode:罗马数字转整数【13】

LeetCode:罗马数字转整数[13] 题目描述 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 罗马数字 2 写做 II ,即为两个并列的 1.12 写做 XII ,即为 X + II . 27 写做  XXVII, 即为 XX + V + II . 通常情况下,罗马数字中小的数字在大的数字的右边.但也存在特例,例如 4 不写做 IIII,而是 IV.数字 1 在数字 5 的左边

LeetCode:下一个排列【31】

LeetCode:下一个排列[31] 题目描述 实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列. 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列). 必须原地修改,只允许使用额外常数空间. 以下是一些例子,输入位于左侧列,其相应输出位于右侧列.1,2,3 → 1,3,23,2,1 → 1,2,31,1,5 → 1,5,1 题目分析 什么样的排列将产生下一个更大的数字呢? 观察上面这个图,我们需要将数字 a[i-1]替换为位于其右侧区域的数

LeetCode:组合总数II【40】

LeetCode:组合总数II[40] 题目描述 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的每个数字在每个组合中只能使用一次. 说明: 所有数字(包括目标数)都是正整数. 解集不能包含重复的组合. 示例 1: 输入: candidates = [10,1,2,7,6,1,5], target = 8, 所求解集为: [ [1, 7], [1, 2, 5], [2, 6],

LeetCode:四数之和【18】

LeetCode:四数之和[18] 题目描述 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组. 注意: 答案中不可以包含重复的四元组. 示例: 给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0. 满足要求的四元组集合为:[ [-1, 0, 0, 1], [-2, -1, 1, 2]