Ikki's Story IV-Panda's Trick - 竞赛题解

也算是2-sat学习的一个节点吧

终于能够自己解决一道2-sat的题了


·题目

一个圆上有n个点按顺时针编号为 0~n-1 ,有m条边连接一些点(无自环无重边),每条边要么在圆内,要么在圆外。求是否存在一种方案(方案即每条边在圆内还是圆外)使得边之间不存在交点。

如果存在,输出"panda is telling the truth...",否则输出"the evil panda is lying again"。

(额……多组数据,规模一般,2-sat能过就对了)


·解析

由于一条边要么在圆内,要么在圆外,这就相当于两个状态,而每条边就是一个变量——这就形成了一个2-sat问题。

首先处理一下输入:因为点的个数其实没有任何影响( ̄▽ ̄)",我们只需要保存边,显然边 (u,v) 等同于 (v,u) (画图即可证明),为了方便,我们在读入边(a,b)时,稍微处理一下,使a<b。

简单地推理一下,如果两条边(a,b),(c,d)相交,则必然满足 \(a<c<b<d\ ||\ b<a<d<c\),且(a,b),(c,d)同在圆内/外

根据这个简单的性质,我们定义点 \((i<<1)\) 和 \((i<<1|1)\) 分别表示边 i 在圆内、圆外。如果 边i 和 边j 相交(用上面的性质判断),则 (i<<1) 和 (j<<1|1) 、(i<<1|1) 和 (j<<1) 之间都存在一条无向边;同时我们还要存一个反图,后面求强连通分量要用。

建完图后,我们先对所有点进行一次DFS,当某一个点的DFS退出时,将它压入栈内(这里不好解释,看代码就明白了(●'◡'●))。再从栈顶取出点,从该点开始DFS,接下来的所有能通过反图边到达的点都和起点属于同一个强连通分量,直到栈空。这里建议手写栈,STL的没有必要QwQ

最后判断对于每个 边i(即变量),点(i<<1) 和 点(i<<1|1) 是否处于一个连通块内,如果存在这样的i,则不成立,否则成立~

这样就做完了,没什么细节,就是注意存反图的时候别写丑了。


·源代码

(尽量把注释写的详细一点,希望大家能够看懂( ̄︶ ̄*))

/*Lucky_Glass*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=500;
struct EDGE{
int to,nxt;
EDGE(){}
EDGE(int _to,int _nxt):to(_to),nxt(_nxt){};
}edg[(N*2)*(N*2)*2+5][2];
int adj[N*2+5][2],edgtot[2];
void AddEdge(int u,int v,int knd){
edg[++edgtot[knd]][knd]=EDGE(v,adj[u][knd]);
adj[u][knd]=edgtot[knd];
}
int n;
int inp[N*2+5][2],mem[N*2+5],blk[N*2+5];
bool vis[N*2+5];
void DFS1(int u){ //这里是原图
vis[u]=true;
for(int i=adj[u][0];i!=-1;i=edg[i][0].nxt){
int v=edg[i][0].to;
if(vis[v]) continue;
DFS1(v);
}
mem[++mem[0]]=u; //退出DFS时压栈
}
void DFS2(int u,int id){ //这里是反图
vis[u]=true;blk[u]=id; //id是连通块编号,blk[u]表示u所属连通块
for(int i=adj[u][1];i!=-1;i=edg[i][1].nxt){
int v=edg[i][1].to;
if(vis[v]) continue;
DFS2(v,id);
}
}
bool Solve(){
memset(vis,false,sizeof vis);
for(int i=0;i<2*n;i++) //DFS遍历每一个点,求出DFS退出栈
if(!vis[i]) //O(n)-每个点只访问一次
DFS1(i);
//mem[]是手写栈,mem[0]是栈大小
memset(vis,false,sizeof vis);
for(int i=2*n;i>0;i--) //实际上是从栈顶元素,总共2*n个点
if(!vis[mem[i]])
DFS2(mem[i],i);
for(int i=0;i<n;i++) //判断每一条边
if(blk[i<<1]==blk[i<<1|1]) //只要一条边不符合条件
return false;
return true;
}
void Clear(){
// memset(edg,0,sizeof edg); 这里没必要清空
memset(adj,-1,sizeof adj);
edgtot[0]=edgtot[1]=0; //用链表存图的reader们注意这个
}
int main(){
while(~scanf("%*d%d",&n)){
Clear(); //注意清空图!
for(int i=0;i<n;i++){
scanf("%d%d",&inp[i][0],&inp[i][1]);
if(inp[i][0]>inp[i][1]) swap(inp[i][0],inp[i][1]);
}
//choose i -> i<<1
//not choose i -> i<<1|1
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++){
bool A=(inp[i][0]<inp[j][0] && inp[j][0]<inp[i][1] && inp[i][1]<inp[j][1]);
bool B=(inp[j][0]<inp[i][0] && inp[i][0]<inp[j][1] && inp[j][1]<inp[i][1]);
//判断是否相交
if(A||B){ //同时处理正反图,AddEdge(u,v,0/1)表示在正/反图中连接u->v的边,因为是无向边,所以需要相互连
AddEdge(i<<1,j<<1|1,0);AddEdge(j<<1|1,i<<1,1);
AddEdge(i<<1|1,j<<1,0);AddEdge(j<<1,i<<1|1,1);
AddEdge(j<<1,i<<1|1,0);AddEdge(i<<1|1,j<<1,1);
AddEdge(j<<1|1,i<<1,0);AddEdge(i<<1,j<<1|1,1);
}
}
bool res=Solve();
printf("%s\n",res? "panda is telling the truth...":"the evil panda is lying again");
}
return 0;
}

\(\mathcal THE\ END\)

\(\mathcal Thanks\ for\ reading!\)

竞赛题解 - Ikki's Story IV-Panda's Trick的更多相关文章

  1. poj 3207 Ikki's Story IV - Panda's Trick (2-SAT)

    http://poj.org/problem?id=3207 Ikki's Story IV - Panda's Trick Time Limit: 1000MS   Memory Limit: 13 ...

  2. POJ 3207 Ikki's Story IV - Panda's Trick

    Ikki's Story IV - Panda's Trick Time Limit: 1000MS   Memory Limit: 131072K Total Submissions: 7296   ...

  3. POJ 3207 Ikki's Story IV - Panda's Trick(2-sat问题)

    POJ 3207 Ikki's Story IV - Panda's Trick(2-sat问题) Description liympanda, one of Ikki's friend, likes ...

  4. 【POJ3207】Ikki's Story IV - Panda's Trick

    POJ 3207 Ikki's Story IV - Panda's Trick liympanda, one of Ikki's friend, likes playing games with I ...

  5. POJ 3207 Ikki's Story IV - Panda's Trick (2-sat)

    Ikki's Story IV - Panda's Trick Time Limit: 1000MS   Memory Limit: 131072K Total Submissions: 6691   ...

  6. POJ3207 Ikki's Story IV - Panda's Trick 【2-sat】

    题目 liympanda, one of Ikki's friend, likes playing games with Ikki. Today after minesweeping with Ikk ...

  7. Ikki's Story IV - Panda's Trick

    poj3207:http://poj.org/problem?id=3207 题意::平面上有一个圆,圆的边上按顺时针放着0..n-1共n个点.现在要连m条边,比如a,b,那么a到b可以从圆的内部连接 ...

  8. poj3207 Ikki's Story IV - Panda's Trick 2-sat问题

    ---题面--- 题意:给定一个圈,m条边(给定),边可以通过外面连,也可以通过里面连,问连完这m条边后,是否可以做到边两两不相交 题解: 将连里面和连外面分别当做一种决策(即每条边都是决策点), 如 ...

  9. POJ3207 Ikki's Story IV – Panda's Trick

    Time Limit: 1000MS   Memory Limit: 131072K Total Submissions: 9426   Accepted: 3465 Description liym ...

  10. 图论--2-SAT--POJ Ikki's Story IV - Panda's Trick

    Description liympanda, one of Ikki's friend, likes playing games with Ikki. Today after minesweeping ...

随机推荐

  1. linux下通过NFS将远程磁盘mount到本地

    最近由于项目原因需要和其他两家公司对接,需要取对方服务器中的图像数据,原本约定是三方都通过http协议来进行通讯,奈何对接方不配合,说文件就在他们服务器放着,怎么取他们不管.所以采取将对方服务器磁盘挂 ...

  2. RocketMQ读书笔记5——消息队列的核心机制

    [Broker简述] Broker是RocketMQ的核心,大部分“重量级”的工作都是由Broker完成的,包括: 1.接受Producer发过来的消息: 2.处理Consumer的消费信息请求: 3 ...

  3. linux 的 磁盘管理

    1. 查看信息 1.1 查看磁盘信息 在linux中如果需要查看磁盘信息,需要使用df和du命令. df: 列出文件系统中整个磁盘的使用量 du:评估文件系统中磁盘的使用量,经常用来推算目录所占的容量 ...

  4. c++ 判断是64还是32位系统

    1.IsWow64Process 确定指定进程是否运行在64位操作系统的32环境(Wow64)下. 语法 BOOL WINAPI IsWow64Process( __in HANDLE hProces ...

  5. 柔性数组成员 (flexible array member)-C99-ZZ

    学习flexible array member是因为阅读Redis源码遇到的,sds.h中一开始就用到了. ============================================== ...

  6. mongodb 3.4分片复制集配置

    1:启动三个实例 mongod -f /home/mongodb/db27017/mongodb27017.conf mongod -f /home/mongodb/db27018/mongodb27 ...

  7. Linux->Ubuntu下配置telnet环境

    1.首先查看telnet运行状态 netstat -a | grep telnet 输出为空,表示没有开启该服务 2.安装openbsd-inetd apt-get install openbsd-i ...

  8. 【Leetcode】【Easy】Same Tree

    Given two binary trees, write a function to check if they are equal or not. Two binary trees are con ...

  9. 实现UILabel渐变色效果

    实现UILabel渐变色效果 效果如下图: 源码: // // CombinationView.h // ChangeColorLabel // // Created by YouXianMing o ...

  10. 安装和测试Kafka

    本文主要介绍如何在单节点上安装 Kafka 并测试 broker.producer 和 consumer 功能. 下载 进入下载页面:http://kafka.apache.org/downloads ...