算法问题实战策略 MEETINGROOm

地址

解答

todo

错误代码

  1 // Tarjan_Scc.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
  2 //
  3
  4 #include "pch.h"
  5
  6
  7 #include <algorithm>
  8 #include <iostream>
  9 #include <vector>
 10 #include <stack>
 11
 12 using namespace std;
 13
 14 vector<vector<int>> adj;
 15
 16 vector<int> sccId, discovered, finished;
 17 stack<int> st;    //保存顶点序号的栈
 18 int sccCounter, vertexCounter;
 19
 20 //返回以here为根节点的子树中
 21 //能够到达后向边的最小发现顺序
 22 int scc(int here) {
 23     int ret = discovered[here] = vertexCounter++;
 24     //将here存入栈,here的所有后代节点都会在here之后进栈
 25     st.push(here);
 26
 27     for (int i = 0; i < adj[here].size(); i++) {
 28         int there = adj[here][i];
 29         //(here,there)是树边
 30         if (discovered[there] == -1)
 31             ret = min(ret, scc(there));
 32         else if (discovered[there] < discovered[here] && finished[there] != 1)
 33             ret = min(ret, discovered[there]);
 34     }
 35
 36     //判断here是否为强联通分量的根节点
 37     if (ret == discovered[here]) {
 38         //以here为根节点的子树中,将剩余所有顶点全部绑定为同一分量
 39         while (true) {
 40             int t = st.top();
 41             st.pop();
 42             sccId[t] = sccCounter;
 43             if (t == here) break;
 44         }
 45         ++sccCounter;
 46     }
 47
 48     finished[here] = 1;
 49     return ret;
 50 }
 51
 52
 53 //tarjan 的scc算法
 54 vector<int> tarjanSCC() {
 55     //数组和计数器的初始化
 56     sccId = discovered = finished = vector<int>(adj.size(), -1);
 57     sccCounter = vertexCounter = 0;
 58
 59     //对所有顶点调用scc()
 60     for (int i = 0; i < adj.size(); ++i)
 61         if (discovered[i] = -1) scc(i);
 62     return sccId;
 63 }
 64
 65
 66 //========================================================================
 67 //图的领接表表示法
 68 //vector<vector<int>> adj;
 69
 70 bool disjoint(const pair<int, int>& a, const pair<int, int>& b){
 71     return a.second <= b.first || b.second <= a.first;
 72 }
 73
 74 //如果meetings[]表示各队提出的开会时间
 75 //则将此题转换为2-SAT问题后生成蕴含图
 76 //第i个团队需要选择meetings[2*i]或meetings[2*i+1]时候之一开会
 77 void makeGraph(const vector<pair<int, int>>& meetings)
 78 {
 79     int vars = meetings.size();
 80
 81     //每个变量对应图的两个顶点
 82     adj.clear(); adj.resize(vars*2);
 83     for (int i = 0; i < vars; i += 2) {
 84         //各团队需要选择第i号和第j号会议之一
 85         //添加(i or j )句子
 86         int j = i + 1;
 87         adj[i * 2 + 1].push_back(j * 2);
 88         adj[j * 2 + 1].push_back(i * 2);
 89     }
 90
 91     for (int i = 0; i < vars; ++i) {
 92         for (int j = 0; j < i; ++j) {
 93             //第i号会议和第j号会议重叠
 94             if (!disjoint(meetings[i], meetings[j])) {
 95                 //放弃第i个会议 或者放弃第j个会议
 96                 //添加 (~i or ~j)子句
 97                 adj[i * 2].push_back(j * 2 + 1);
 98                 adj[j * 2].push_back(i * 2 + 1);
 99             }
100         }
101     }
102 }
103
104
105 vector<int> solve2SAT()
106 {
107     int n = adj.size() / 2;
108     vector<int> label = tarjanSCC();
109
110     for (int i = 0; i < 2 * n; i += 2)
111         if (label[i] == label[i + 1])
112             return vector<int>();
113
114     vector<int> value(2 * n, -1);
115
116     vector<pair<int, int>> order;
117     for (int i = 0; i < 2 * n; i++)
118         order.push_back(make_pair(-label[i], i));
119     sort(order.begin(),order.end());
120
121     for (int i = 0; i < 2 * n; ++i) {
122         int vertex = order[i].second;
123         int variable = vertex / 2, isTrue = vertex % 2;
124         if (value[variable] != -1) continue;
125         value[variable] = !isTrue;
126     }
127     return value;
128 }
129
130
131
132
133 int main()
134 {
135     int n;
136     cin >> n;
137
138     while (n--) {
139         int m;
140         cin >> m;
141         vector<pair<int, int>> meetings;
142         while (m--) {
143             int a, b, c, d;
144             cin >> a >> b >> c >> d;
145             meetings.push_back(make_pair(a,b));
146             meetings.push_back(make_pair(a, b));
147         }
148         makeGraph(meetings);
149
150         vector<int> v = solve2SAT();
151
152         int i = 9;
153
154     }
155
156 }

原文地址:https://www.cnblogs.com/itdef/p/11822234.html

时间: 2024-10-10 22:56:46

算法问题实战策略 MEETINGROOm的相关文章

《算法问题实战策略》-chaper7-穷举法

关于这一章节<算法实战策略>有一段概述问题,我认为对于编程人员来说非常有价值,故在这里进行如下的摘抄: 构想算法是很艰难的工作.相比大家都经历过,面对复杂的要求只是傻乎乎地盯着显示器,或者不经过深思熟虑就开始打键盘,结果还要辛辛苦苦修改变得一塌糊涂的代码.经过这些磨难,各位就能切身体会到设计算法的重要性. 与通常所想不同,支配设计算法的并不是一时的灵感,而是许多策略性的选择.构想算法不仅需要理解问题的特性,还要理解执行时间和占用内存空间之间的对立关系,而且要会选择适当的数据结构. 算法设计范式

《算法问题实战策略》-chaper32-网络流

基本的网络流模型: 在图论这一块初步的应用领域中,两个最常见的关注点,其一时图中的路径长度,也就是我们常说的的最短路径问题,另一个则是所谓的“流问题”. 流问题的基本概念: 首先给出一张图. 其实所谓“网络流”,其模型是非常有现实意义的.我们将该图视为计算机网络结构.此图中,s称其为源点而t称其为汇点.这个图中剩余的源泉代表网络设备,连接个顶点的边线表示连接两个设备的数据线缆,边的权值表示这条线缆能够传输的最大数据. 首先我们应该能够注意到,有向路径<s,t>就是一条传输路线,而这条传输数据的

《算法问题实战策略》——chaper9——动态规划法技巧

Q1: 数字游戏: 两个人(A.B)用n个整数排成的一排棋盘玩游戏,游戏从A开始,每个人有如下操作: (1)    拿走棋盘最右侧或者最左侧的棋子,被拿走的数字从棋盘中抹掉. (2)    棋盘中还剩下两个以上的数字的时候,可以把棋盘最右侧或者最左侧的两个数字抹掉 当棋盘上的所有数字消失之后,游戏结束,谁拿的棋子代表的整数之和较大谁赢,现在假设两个游戏者都是聪明的,给出长度为n的序列,请计算游戏结束之后A的分数和B的分数的差值. 分析:其实相似的问题在<训练指南>当中曾经分析过,那个题目叫做“

《算法问题实战策略》-chaper21-树的实现和遍历

这一章节开始介绍一个数据结构中的一个基本概念——树. 我们从数据结构的解读来解释树结构的重要性,现实世界的数据除了最基本的线性结构(我们常用队列.数组和链表等结构表征),还有一个重要的特性——层级结构需要我们去表征,例如世界杯的对阵表.遗传系谱图等等,这时候我们基于对现实世界的抽象,会很自然的理解为什么会有树这样一个数据结构. 而树这种数据结构也是能够分类的,我们将每个节点记录某种抽象的概念或者具象的事物,这样用来表征一种从属关系,我们称其为抽象型数据结构的树.或者将每个节点储存一些数据,基于这

《算法问题实战策略》-chaper13-数值分析

这一章节主要介绍我们在进行数值分析常用的二分.三分策略. 首先介绍二分. 其实二分的思想很好理解并且笔者在之前的一些文章中也有所渗透,对于二次函数甚至单元高次函数的零点求解.线段树还有<algorithm puzzle>当中的“切割钢条”问题,都是基于二分思想. 下面我们通过具体的问题来应用二分这种数值分析的策略. Ex1:按揭贷款 以P%的年利率借贷N元后,在M个月内,以每月还C元的方式还贷.贷款期限内,按照如下形式计算贷款余额. (1)    贷款余额从余额N元开始. (2)    美国一

算法问题实战策略 QUADTREE

地址 https://algospot.com/judge/problem/read/QUADTREE 将压缩字符串还原后翻转再次压缩的朴素做法 在数据量庞大的情况下是不可取的 所以需要在压缩的情况下进行翻转 图片可以分成四块 每块在颜色不统一的情况下又会分成四块 那么翻转也可以采取这种逐步将问题分解成小块翻转 然后再处理大块算法 最后的到结果的算法 代码如下 #include <iostream> #include <string> using namespace std; /*

算法问题实战策略 DICTIONARY

地址 https://algospot.com/judge/problem/read/DICTIONARY 解法 构造一个26字母的有向图 判断无回路后 就可以输出判断出来的字符序了 比较各个字母的先后次序不必用一个单词分别同其他单词比较 只需要将临近的两个单词一一比较即可 证明如下 算法1 中判断有无回路 采取的是DFS方法 代码 1 #include <iostream> 2 #include <string> 3 #include <vector> 4 #incl

《算法问题实战策略》-chaper14-整数论

Lucas定理: 在组合计数问题中,我们常面临组合数C(n,m)过大而无法直接计算的困境,那么这里的Lucas定理给出了一个较大组合数进行取余运算的一种递归算法. 什么是Lucas定理? Lucas定理的推导证明? 这个推导过程基于二项式定理,基于最后的等式,我们通过过找等是左边和右边x^(tp + r)的系数,即可完成对Lucas定理的证明.但是这里并没有呈现对p为什么是素数的说明. 在这里我们给出Lucas定理的另外一种表达形式: 我个人认为,限定了取模的数p是素数,这样统一了运算,即对于∏

《算法问题实战策略》-chaper15-计算几何-线段相交

这篇文章着力来讨论线段相交这一个问题. 给出两条线段,如何判断这两条线段相交? 如果这两条线段相交,如何求其交点? 线段相交问题通常由于其繁杂的情况种类而让人避而远之,在这里希望通过笔者的简化讨论希望帮读者的思路进行一下梳理. 首先我们尝试画几个几何图像来找一下线段相交的一些不同的情况,这里需要注意,可能有读者会好奇,这些直观上来看没什么差别的相交情况,我们为什么为认为他们是不同的呢?答案是,这里我们需要将几何特征用代数表达是进行判断,因此不同的几何特征虽然都表示线段相交,但是对应的代数表达式不