时间计算题100道_时间不够用?题目做不完?做题攻略和时间分配来啦

本文详细介绍了考研英语、政治、数学的时间分配策略与答题技巧,帮助考生合理规划考试时间,提高答题效率。
部署运行你感兴趣的模型镜像

来源微信公众号硬核考研 每天免费分享考研资料

各位同学们,大家晚上好呀!

5403ae657f367516e5a895e0f0e4f026.png

10月还剩下了一个小尾巴,不知道大家在做真题时的时间怎样分配,很多考研儿们都会有时间不够用,题目做不完的烦恼。今天小编就来给大家解答。

考研英语

英语一

1、完型填空(10分,每个0.5)2、阅读partA,就是常说的阅读部分(传统阅读部分),共4篇文章(40分,每个2分)3、阅读partB,俗称新题型(10分,每个2分)4、阅读partC,也就是翻译(10分,1篇文章5个划线部分,每个2分)5、作文(共30分),作文A为应用型小作文(写私人和公务信、备忘录、报告等,约100词,共10分),作文B大作文(一般为看图描述性、叙述性、说明性、议论性作文,约160-200词,共20分)

英语二

1、完型填空(10分,每个0.5)

2、阅读partA,就是常说的阅读部分(传统阅读部分),共4篇文章(40分,每个2分)

3、阅读partB,俗称新题型(10分,每个2分)

4、翻译(一个或几个段落,英译汉,15分)

5、作文(共25分),作文A为应用作文写信、通知、告示等(共10分)作文二大作文一般为看图作文(共20分)

时间控制

完型:15分钟左右

阅读:英语一每篇文章18-20分钟,英语二每篇文章17分钟,难度略高的可以适当增加2-3分钟,然后通过其他题型来进行适当找补。

新题型:尽量20分钟以内

翻译:20分钟

作文:小作文15-20分钟,大作文30分钟。

建议答题卡做一题涂一空。

做题顺序:

①大作文>1篇阅读>小作文>1篇阅读>新题型>1篇阅读>翻译>1篇阅读>完型(常规推荐方案)

②大作文>小作文>2篇阅读>翻译>1篇阅读>新题型>1篇阅读>完型。(适合依赖考前突击背诵作文以及大脑进入状态慢的同学,先通过作文或模板的默写来进入状态,防止作文短时快速记忆的遗忘)

③上述1、2方法调整成4篇阅读一起做(适合那种需要高强度做题保持头脑一直处在阅读思维状态的同学们,如果其他顺序都不合适,只适合这种方法,也不需要刻意分散4篇阅读)

④顺序式做题法,即按照考卷顺序做题,这种做题顺序对于粗心大意漏题严重者特别有用!

完形最后做的原因是一个空0.5分,如果最后要是实在是没什么时间,只能蒙了!

考研政治

其中单选题16(16*1)分,多选题34(17*2)分,分析题50(5*10)分,共计38道题目。

时间分配

180分钟,建议按序做题

首先,6-10-2定律,这180分钟的分配一般遵循60分钟,100分钟,20分钟的原则。就是60分钟选择题,100分钟分析题,最后20分钟是补充检查时间,当然,同学们可以根据自己的情况自己再做调整,但是补充检查的20分钟是一定要有的。具体来说单选题相对简单,建议15-20分钟左右做完。多选题难度较大,建议1-2分钟一道题,30-35分钟左右做完。分析题建议每道题目20-25分钟。

  • 注意:做完选择题之后先把答题卡涂好,以防后面因回答分析题耗时较长导致最后没时间涂卡。

考研数学

试卷结构

选择题:8题(每题4分);填空题:6题(每题4分);解答题:9题(每题10分左右);

满分150分,考试时间3小时。

高等数学:84分,占56%(4道选择题,4道填空题,5道大题);

线性代数:33分,占22%(2道选择题,1道填空题,2道大题);

概率论与数理统计:33分,占22%(2道选择题,1道填空题,2道大题)。

注意:数学二不考概率论与数理统计,这一科的分值和试题全加到高等数学中。

考研数学有三部分,即高等数学(微积分)、线性代数和概率统计,其中数学二不考概率统计。在最后两周的时间内,应该多花一些时间去复习能尽快提高成绩的学科及自己尚未完全掌握的重要知识点,这样才能在最短的时间内产生最大的效益。

自己擅长的科目和题型不应再花太多时间。而自己不擅长的一些科目和题型,应多花时间去突击复习,成绩应该会较快提高。比如数学一中的线面积分、无穷级数,还有特征值、特征向量和实对称矩阵的对角化等等。概率统计中的二维随机变量和数理统计中的内容,多复习、多记忆也会收到很好效果的。

数学一关于高等数学部分的考试重点在定积分、重积分、线面积分、无穷级数等章,而数学二、三的高等数学(微积分)部分的考试重点在微分中值定理、定积分等后面几章。

复习线性代数最重要是向量的线性相关性、线性方程组、特征值与特征向量、二次型与正定矩阵等内容。这几章题型变化多,知识点的衔接与转换非常集中,便于命制综合题。

复习概率统计的重点是多维随机变量及其分布以及随机变量的数字特征。

填空题

填空题命题特点

填空题考查都是比较基础的知识点,主要是考研数学中的三基本:基本概念、基本原理、基本方法以及一些基本的性质。同时,重点考查考生的基本运算能力。

填空题答题技巧

填空题题目的难度与选择题不相上下,也是适中。这类题一般是需要一定技巧的计算,但不会有太复杂的计算题。所以,关键就是如何用最简单、最有效的方法来算出结果。

那么,填空题如何提高答题准确率呢?

一是勤于动手练题。平时光看不练,或只是随便在草稿上划两下,没有进行一定量的训练的话,考试的时候就容易出错。这就要求我们的小研们平时对一些基本的运算题,最起码是每一种类型的计算题都拿出一定量来进行练习,保持题感。

二借助特殊方法。填空题本身包含着特殊的方法和技巧,但是,若方法不当就会本来很简单的题做成了很复杂的题。比如用“代入法”可以直接得出结果的,却按解答题的步骤来,这就容易造成填空题失分,也耽误考试时间。

进行有针对性的高效复习———综合题的解题策略

所谓综合题就是考查多个知识点,即把前后章节的知识综合起来进行考核的试题。这类题目要求考生要学会分析问题,抓联系、抓总结,切实掌握与知识点之间的联系,真正理解基本概念的实质,融会贯通各概念之间的内在联系,形成知识网来分析问题和解决问题。

数学考研试题大部分是复合型的。在复习线性代数时,一定要以线性方程组为核心,前后融会贯通,灵活运用所学知识来分析问题和解决问题,不要将它们孤立割裂开来。比如行列式、矩阵、向量、线性方程组是线性代数的基本内容,它们不是孤立割裂的,而是相互渗透,紧密联系的。在复习概率统计时,小研们要灵活运用所学知识,建立正确的概率模型,综合运用极限、连续、导数、积分、广义积分、二重积分以及级数等知识去分析和解决实际问题,提高解综合题的能力。

策略之一——缺步解答:对一个疑难问题,确实啃不动时,一个明智的解题策略是,将它划分为一个子问题或一系列的步骤,先解决问题的一部分,即能解决到什么程度就解决到什么程度,能演算几步就写几步,每进行一步就可得到这一步的分数。如从最初的语言文字转化成数学语言和相应数学公式,把条件和目标译成数学表达式等,都能得分。

策略之二——跳步解答:解题过程卡在一中间环节上时,可以承认中间结论,往下推,看能否得到正确结论,如得不出,说明此途径不对,立即改变方向,寻找它途;如能得到预期结论,就再回头集中力量攻克这一过渡环节。

如果题目有两问,第一问做不上,可以把第一问当做已知条件,先完成第二问,即为跳步解答。

b52ba0f814c8e147c8242c9b9b22e0c8.png

您可能感兴趣的与本文相关的镜像

ComfyUI

ComfyUI

AI应用
ComfyUI

ComfyUI是一款易于上手的工作流设计工具,具有以下特点:基于工作流节点设计,可视化工作流搭建,快速切换工作流,对显存占用小,速度快,支持多种插件,如ADetailer、Controlnet和AnimateDIFF等

<think>我们使用Tarjan算法解决2-SAT问题,并应用于洛谷P4171 [JSOI2010] 满汉全席。 题目描述:有n种食材,每种食材有两种烹饪方式(满式汉式)。同时有m个评委,每个评委有两个要求,每个要求指定一种食材的烹饪方式(如:食材i必须用满式,或者食材j必须用汉式)。每个评委的要求满足至少一个即可。问是否存在一种烹饪方案满足所有评委的要求。 2-SAT问题:对于每个食材i,定义两个布尔变量: x_i = true 表示第i种食材用满式 x_i = false 表示第i种食材用汉式 但是为了方便,我们通常用两个点表示一个变量的真假(即用两个点表示一个食材的两种选择): 我们用点 i 表示 x_i 为真(即满式) 用点 i+n 表示 x_i 为假(即汉式) 每个评委的两个条件形如:(A 或 B),其中AB都是关于某个变量的取值要求。 例如:一个评委要求“食材i必须用满式或者食材j必须用汉式”,那么可以表示为:(x_i 为真) 或 (x_j 为假) 这个条件等价于:如果满足前半部分(即x_i为假),那么必须满足后半部分(即x_j为假);同时,如果满足后半部分(即x_j为真),那么必须满足前半部分(即x_i为真)。 因此,我们可以将条件转化为两条有向边: ¬A → B ¬B → A 具体地: x_i为假(即点i+n) → x_j为假(点j+n) [因为如果x_i为假,那么必须满足x_j为假] x_j为真(即点j) → x_i为真(点i) [因为如果x_j为真(即是汉式),那么必须满足x_i为真] 更一般地,对于条件 (A ∨ B),我们可以转化为: ¬A → B ¬B → A 在图中,我们建立对应的有向边。 然后,我们使用Tarjan算法求强连通分量(SCC),并缩点。如果对于某个变量i,其真值点(i)假值点(i+n)在同一个强连通分量中,则说明无解(因为矛盾:i必须为真又必须为假)。 否则,存在解。 对于输出方案,我们通常利用Tarjan算法得到的SCC编号(即缩点后的编号)来构造。 根据引用[2]引用[3]:Tarjan算法得到的SCC编号实际上是反拓扑序(即先求出的SCC编号大,后求出的编号小,因为栈底的是最先被遍历的,所以编号小)。 而求解2-SAT需要按照逆拓扑序(即从拓扑排序的末尾开始)给变量赋值。 具体规则:对于变量i,我们选择其真值点假值点中所在SCC编号较小的那个值作为该变量的值(因为较小的编号在拓扑序中更靠后,而按照逆拓扑序求解,我们实际上先处理的是编号大的,然后处理编号小的。但是这里有一个转换:如果变量x的拓扑序在¬x之后,那么取x为真。而Tarjan的SCC编号是反拓扑序,所以x的SCC编号如果小于¬x的编号,那么x的拓扑序实际上在¬x之前(因为反拓扑序中编号小的拓扑序大),那么按照规则应该取x为假?这里需要澄清)。 引用[3]中明确指出:因为Tarjan求得的SCC编号相当于反拓扑序,所以如果x所在SCC编号在¬x之前(即x的编号比¬x的编号小),那么取x为真。为什么呢? 因为逆拓扑序是从拓扑序的末尾开始,而反拓扑序(即Tarjan的SCC编号顺序)中,编号小的节点在拓扑序中实际上是大的(即先出栈的节点在拓扑序中排在后面,后出栈的排在前面?)。实际上,我们通常认为在同一个强连通分量中无所谓,而同强连通分量之间的边,我们考虑缩点后的图,这个图是有向无环图(DAG)。在缩点后的图中,如果有一条边从SCC1指向SCC2,那么SCC1应该在SCC2之前(拓扑序中SCC1<SCC2)。而Tarjan算法得到的SCC编号是递减的(即先找到的SCC编号大,后找到的SCC编号小),所以SCC编号小的节点在拓扑序中实际上是在后面(即拓扑序是从大到小)。 规则:我们取变量x的值为:如果x的SCC编号小于¬x的SCC编号,则取x为真;否则取假。 为什么?因为这样选择,我们实际上选择了拓扑序较大的那个取值(因为SCC编号小意味着拓扑序大),而按照逆拓扑序(从拓扑序的末尾开始)我们选择的是拓扑序较大的取值,这样会产生矛盾。 但题目只要求判断是否有解,所以需要输出方案。 具体步骤: 1. 建图:n个食材,共2*n个点(1到n表示满式,n+1到2*n表示汉式)。 注意:题目输入中,一个评委的两个要求,每个要求是一个字符串,如"m1"表示第1种食材用满式,"h2"表示第2种食材用汉式。 对于每个条件,我们拆分成两个点,并建立两条边。 2. 使用Tarjan算法求所有强连通分量,并记录每个点所在的SCC编号。 3. 检查每个食材i(1<=i<=n): 如果点i点i+n在同一个强连通分量中,则无解。 4. 如果所有食材都满足点i点i+n在同一个强连通分量,则有解。 注意:建图时,需要将输入的字符串转换为对应的点编号。 例如:"m1" -> 点1(表示食材1用满式,即x1为真) "h1" -> 点1+n(表示食材1用汉式,即x1为假) 对于条件:A或B,其中AB是两个条件(分别对应两个点),那么我们需要建立: ¬A -> B ¬B -> A 如何表示¬A?对于A代表的点p,¬A对应的点就是其对立点(如果p<=n,则对立点是p+n;如果p>n,则对立点是p-n)。 但是,我们也可以这样处理: 设条件A:要么是m要么是h,后面跟一个数字id。 对于条件A,我们定义: 若为m id,则对应的真值点为id,假值点为id+n 若为h id,则对应的真值点为id+n,假值点为id (因为h id表示汉式,即x_id为假,所以用id+n表示这个条件要求假值点?对,我们要统一变量定义) 重新定义:对于每个食材i,我们定义: 点i:表示采用满式(x_i为真) 点i+n:表示采用汉式(x_i为假) 那么: 条件"m i" 表示:要求点i(即要求x_i为真) 条件"h i" 表示:要求点i+n(即要求x_i为假) 那么,一个评委的两个条件:A 或 B,其中AB分别是两个条件(分别对应一个点,我们设为ab)。 那么,这个条件等价于:¬A → B ¬B → A ¬A是什么?如果A是点i(表示要求x_i为真),那么¬A就是x_i为假,即点i+n。 同理,如果B是点j+n(表示要求x_j为假),那么¬B就是x_j为真,即点j。 因此,对于条件A或B,我们添加两条边: 从¬A指向B:即从A的对立点指向B 从¬B指向A:即从B的对立点指向A 具体操作: 设条件A为字符串,如"m1",我们可以得到: 如果第一个字符是'm',则真值点编号为id(整数部分),对立点(假值点)为id+n 如果第一个字符是'h',则真值点编号为id+n,对立点(假值点)为id 注意:这里真值点表示这个条件成立时对应的点,假值点表示这个条件成立时对应的点。 因此,对于条件A,我们用两个变量表示: 节点a:条件成立时对应的点(即真值点) 节点a的否定:即对立点(即条件成立时对应的点) 那么,对于条件A或B,我们添加边: 从条件A的否定(即a的对立点)指向条件B的节点(即b) 从条件B的否定(即b的对立点)指向条件A的节点(即a) 建图成后,跑Tarjan,然后检查每个i(1<=i<=n): scc_id[i] scc_id[i+n] 是否相等?如果相等,则无解;否则有解。 代码框架: n, m = 食材种数,评委数 初始化图:共2*n+1个点(点编号从1到2*n) for 每个评委的条件: 读入两个字符串,如s1, s2 将s1转换为节点a(真值点)它的对立点na 将s2转换为节点b(真值点)它的对立点nb 添加两条边: na -> b (如果条件1成立,则条件2必须成立) nb -> a (如果条件2成立,则条件1必须成立) Tarjan(总点数=2*n) for i in 1..n: if scc_id[i] == scc_id[i+n]: return "BAD" return "GOOD" 注意:Tarjan算法中,我们通常用栈来记录当前搜索的节点,以及记录每个节点的dfnlow。 由于题目只需要判断是否有解,需要输出方案,因此我们只需要判断每个变量的两个点是否在同一个SCC中。 下面我们根据题目输入输出格式,注意多组数据。 题目输入格式: 第一行:整数T,表示测试数据组数。 每组数据: 第一行:两个整数n, m 接下来m行,每行两个字符串,表示一个评委的两个要求。 输出格式: 每组数据输出一行:如果可行输出"GOOD",否则输出"BAD"。 我们按照上述方法实现即可。 但是,我们也可以考虑优化:建图时,对于每个条件,我们直接得到两个真值点(ab),以及它们的对立点(nanb),然后建边na->bnb->a。 示例:一个评委要求:m1 h1 (即食材1用满式或者食材1用汉式) 真值点a:对于"m1" -> 点1 真值点b:对于"h1" -> 点1+n 对立点na:点1的对立点就是1+n 对立点nb:点1+n的对立点就是1 添加边:na->b -> 1+n -> 1+n (边从1+n到1+n?这是自环,可以忽略,但加上也无妨) nb->a -> 1 -> 1 这样建图后,实际上没有添加有效的边?但是注意,这个条件实际上是永真的(因为食材1要么用满式要么用汉式,所以这个条件一定满足)。所以影响。 因此,我们按照上述方法建图即可。 下面是使用Tarjan算法解决该问题的详细步骤: 1. 初始化:总点数tot=2*n,建图(邻接表),初始化dfn, low, stk, inStack, scc_id等数组,以及时间栈顶指针。 2. 遍历所有点(1到2*n),如果dfn[i]为0,则进行Tarjan(i)。 3. Tarjan算法: dfn[u] = low[u] = ++index; 入栈,标记inStack[u]=true 遍历u的邻接点v: 如果dfn[v]为0,则递归Tarjan(v),然后low[u]=min(low[u], low[v]) 如果dfn[v]为0且v在栈中,则low[u]=min(low[u], dfn[v]) 如果dfn[u]==low[u]: 将栈中从u到栈顶的所有节点弹出,标记它们属于同一个SCC(scc_count++),并标记这些节点在栈中。 4. 检查每个i(1<=i<=n): if scc_id[i] == scc_id[i+n] -> 无解。 5. 输出结果。 注意:多组数据,每次要清空图,清空dfn, low, stk, inStack, scc_id等数组,重置时间栈顶指针以及SCC计数。 由于题目数据范围:1<=n<=100, 1<=m<=1000,所以节点最多200个,边最多2000条,Tarjan算法全可行。 下面我们用一个例子验证: 例子:输入样例第一组: 2 2 m3 h1 m1 h3 我们建立变量:食材1食材2(注意题目有2种食材,但条件中出现了3?这里可能是题目描述问题,实际题目中食材编号从1到n,所以样例中应该是3种食材?但题目说2种) 重新检查题目描述:输入格式中,第一个整数n(1<=n<=100)表示食材种数,m(1<=m<=1000)表示评委数。 然后m行,每行两个字符串,每个字符串由一个字符(m或h)一个数字(1到n)组成。 所以,样例输入中的数字应该超过n。但是样例输入: 2 2 m3 h1 -> 这里出现了31,但n=2,所以食材编号应该是12,这里出现了3?可能是题目样例有误?实际上,题目描述中样例输入第一行是1,第二行是2,第三行是3?但题目样例输入如下: 题目样例输入: 2 3 5 m3 h1 m1 m2 m1 h3 h1 m3 h3 m2 2 4 h1 m2 m2 m1 h1 h2 m1 m2 所以,这里第一组数据n=3,m=5,食材编号1,2,3。 因此,我们处理样例第一组: 食材n=3,点编号:1,2,3(满式)4,5,6(汉式,分别对应1,2,3的汉式) 第一个条件:m3 h1 m3 -> 真值点3,对立点3+3=6 h1 -> 真值点1+3=4,对立点1 添加边:6->4 1->3 第二个条件:m1 m2 m1 -> 真值点1,对立点1+3=4 m2 -> 真值点2,对立点2+3=5 添加边:4->2 5->1 第三个条件:m1 h3 m1 -> 1,对立点4 h3 -> 3+3=6,对立点3 添加边:4->6 3->1 第四个条件:h1 m3 h1 -> 4,对立点1 m3 -> 3,对立点6 添加边:1->3 6->4 (注意,这里第一条边1->3已经添加过了,重复添加无影响,但可以避免重复) 第二条边6->4也已经添加过。 第五个条件:h3 m2 h3 -> 6,对立点3 m2 -> 2,对立点5 添加边:3->2 5->6 建图成。 然后跑Tarjan,得到SCC,然后检查: 食材1:点1点4 -> scc_id[1]scc_id[4]是否相等? 食材2:点2点5 食材3:点3点6 如果都同,则有解,否则无解。 实际题目样例输出第一组:GOOD 第二组:n=2, m=4 条件: h1 m2 -> h1:4(真值点), 对立点1; m2:2,对立点5 -> 边:1->2, 5->4 m2 m1 -> m2:2,对立点5; m1:1,对立点4 -> 边:5->1, 4->2 h1 h2 -> h1:4,对立点1; h2:5,对立点2 -> 边:1->5, 2->4 m1 m2 -> m1:1,对立点4; m2:2,对立点5 -> 边:4->2, 5->1 检查:食材1:点1点4 -> 它们是否在同一个SCC? 食材2:点2点5 实际样例输出第二组:BAD 因此,我们按照上述方法实现即可。 由于题目要求,我们只输出是否有解。 现在,我们总结使用Tarjan算法解决P4171的步骤: 1. 读入T(测试数据组数) 2. 对于每组数据: 读入n, m 初始化图:总点数2*n,清空邻接表(大小2*n+1),初始化Tarjan所需数组(dfn, low, inStack, scc_id等),初始化时间戳index=0,栈指针top=0,scc_count=0。 对于m个条件: 读入两个字符串s1, s2 解析s1:第一个字符ch,后面的数字id(字符串转整数) 如果ch=='m',则真值点a = id(注意:id是食材编号,从1开始) 如果ch=='h',则真值点a = id + n 同样解析s2,得到真值点b 得到a的对立点na:如果a<=n,则na=a+n;否则na=a-n 得到b的对立点nb:如果b<=n,则nb=b+n;否则nb=b-n 添加两条有向边:na -> b nb -> a 然后,对每个点(1到2*n)如果dfn[i]为0,则进行Tarjan(i) 检查每个食材i(1<=i<=n): 如果scc_id[i] == scc_id[i+n](注意:i表示满式,i+n表示汉式),则标记无解并跳出循环。 输出结果:如果无解则输出"BAD",否则输出"GOOD" 3. Tarjan算法函数:标准实现。 注意:点编号从1到2*n,所以数组大小要开够。 下面我们写一个伪代码: 由于用户要求使用中文回答,并且需要生成相关问题,我们在回答的最后生成相关问题。 但是,用户的问题是:使用tarjan 2-sat算法解决洛谷P4171 [JSOI2010] 满汉全席的方法。 因此,我们回答的重点是方法步骤,而是代码实现(但可以给出伪代码框架)。 回答结构: 1. 问题转化:将题目条件转化为2-SAT问题。 2. 建图规则:如何根据评委要求建立有向图。 3. 使用Tarjan求强连通分量。 4. 判断是否有解:检查每个变量的两个对立点是否在同一个SCC中。 5. 注意:题目要求输出方案,所以省略方案输出步骤。 最后,生成相关问题。 </think> ### 使用 Tarjan 算法解决 2-SAT 问题(洛谷 P4171) #### 问题转化 1. **变量定义**: 对每种食材 $i$,定义布尔变量: - $x_i = \text{true}$ 表示使用满式烹饪 - $x_i = \text{false}$ 表示使用汉式烹饪 2. **图结构**: - 真值点 $i$ 表示 $x_i$ 为真(满式) - 假值点 $i + n$ 表示 $x_i$ 为假(汉式) 共 $2n$ 个点($1$ 到 $2n$)。 3. **条件转换**: 每个评委的条件如 $(A \lor B)$(例如 `m3 h1`)转换为两条有向边: - $\neg A \to B$(若 $A$ 成立,则 $B$ 必须成立) - $\neg B \to A$(若 $B$ 成立,则 $A$ 必须成立) 其中: - `m i` → 真值点 $a = i$,否定点 $\neg a = i + n$ - `h i` → 真值点 $a = i + n$,否定点 $\neg a = i$ #### 算法步骤 1. **建图**: ```python for _ in range(m): s1, s2 = input().split() a = parse(s1) # 解析条件为真值点编号 b = parse(s2) na = a + n if a <= n else a - n # 计算否定点 nb = b + n if b <= n else b - n add_edge(na, b) # 添加 ¬A → B add_edge(nb, a) # 添加 ¬B → A ``` 2. **Tarjan 求强连通分量(SCC)**: - 通过深度优先搜索计算每个点的 `dfn`(访问顺序) `low`(回溯值)。 - 将节点压入栈,当 `dfn[u] == low[u]` 时弹出栈中节点形成一个 SCC。 - 为每个 SCC 分配唯一 ID(缩点)。 3. **可行性判断**: 检查每个食材 $i$($1 \leq i \leq n$): $$ \text{scc\_id}[i] == \text{scc\_id}[i + n] \quad \Rightarrow \quad \text{无解} $$ 若任意变量 $x_i$ 的真假值在同一 SCC 中,则矛盾(必须同时为真假)。 #### 复杂度分析 - **时间复杂度**:$O(n + m)$,Tarjan 算法线性复杂度。 - **空间复杂度**:$O(n + m)$,存储图及 SCC 信息。 #### 参考代码(C++ 核心部分) ```cpp #include <iostream> #include <vector> #include <stack> #include <cstring> using namespace std; const int MAXN = 1000; vector<int> graph[MAXN]; int dfn[MAXN], low[MAXN], scc_id[MAXN]; bool inStack[MAXN]; stack<int> stk; int index = 0, scc_count = 0; void tarjan(int u) { dfn[u] = low[u] = ++index; stk.push(u); inStack[u] = true; for (int v : graph[u]) { if (!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if (inStack[v]) { low[u] = min(low[u], dfn[v]); } } if (dfn[u] == low[u]) { scc_count++; while (true) { int v = stk.top(); stk.pop(); inStack[v] = false; scc_id[v] = scc_count; if (v == u) break; } } } int main() { int T; cin >> T; while (T--) { int n, m; cin >> n >> m; // 初始化 for (int i = 1; i <= 2 * n; i++) graph[i].clear(); memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(inStack, false, sizeof(inStack)); index = scc_count = 0; // 建图 while (m--) { string s1, s2; cin >> s1 >> s2; int a = stoi(s1.substr(1)) + (s1[0] == 'h' ? n : 0); int b = stoi(s2.substr(1)) + (s2[0] == 'h' ? n : 0); int na = (a <= n) ? a + n : a - n; // 否定点 int nb = (b <= n) ? b + n : b - n; graph[na].push_back(b); graph[nb].push_back(a); } // Tarjan 求 SCC for (int i = 1; i <= 2 * n; i++) if (!dfn[i]) tarjan(i); // 检查可行性 bool valid = true; for (int i = 1; i <= n; i++) { if (scc_id[i] == scc_id[i + n]) { valid = false; break; } } cout << (valid ? "GOOD" : "BAD") << endl; } return 0; } ``` #### 示例分析 - **输入**:`2 4\n h1 m2\n m2 m1\n h1 h2\n m1 m2` - 条件 `h1 m2` → 边 $1 \to 2$ $5 \to 4$ - 最终食材 1 的真假点(1 4)在同一 SCC → **无解(BAD)**。 --- ### 相关问题 1. **如何证明 2-SAT 问题中同一变量的真假值在同一 SCC 时无解?** [^4] 指出:若 $x_i$ $\neg x_i$ 在同一个 SCC,则存在路径 $x_i \to \neg x_i$ $\neg x_i \to x_i$,导致逻辑矛盾($x_i$ 必须同时为真假)。 2. **Tarjan 算法求得的 SCC 编号与拓扑序有何关系?** SCC 编号是**反拓扑序**(编号越小,拓扑序越大)。输出解时需选择 SCC 编号较小的值(引用[^2][^3])。 3. **如何处理非布尔逻辑的 2-SAT 扩展问题(如多值变量)?** 可通过增加变量约束条件转化为标准 2-SAT,但需注意状态空间指数级增长问题。 4. **2-SAT 问题是否有非 Tarjan 的解法?** 是,例如 Kosaraju 算法求 SCC 或随机搜索(如 WalkSAT),但 Tarjan 在效率确定性上更优。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值