竞赛题解 - Ikki's Story IV-Panda's Trick
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的更多相关文章
- 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 ...
- 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 ...
- 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 ...
- 【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 ...
- 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 ...
- 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 ...
- Ikki's Story IV - Panda's Trick
poj3207:http://poj.org/problem?id=3207 题意::平面上有一个圆,圆的边上按顺时针放着0..n-1共n个点.现在要连m条边,比如a,b,那么a到b可以从圆的内部连接 ...
- poj3207 Ikki's Story IV - Panda's Trick 2-sat问题
---题面--- 题意:给定一个圈,m条边(给定),边可以通过外面连,也可以通过里面连,问连完这m条边后,是否可以做到边两两不相交 题解: 将连里面和连外面分别当做一种决策(即每条边都是决策点), 如 ...
- POJ3207 Ikki's Story IV – Panda's Trick
Time Limit: 1000MS Memory Limit: 131072K Total Submissions: 9426 Accepted: 3465 Description liym ...
- 图论--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 ...
随机推荐
- 原生ajax与封装的ajax使用方法
当我们不会写后端接口来测试ajax时,我们可以使用node环境创建一个本地服务器. 1.创建一个本地服务器可参考http://www.cnblogs.com/heyujun-/p/6793900.ht ...
- Linux ->> VMWare Workstation虚拟机里的UBuntu系统安装VMWare-tools
1) mkdir创建一个临时目录 2)复制gz压缩包到临时目录下 3)解压到当前目录 4)运行.pl文件安装 root@ubuntu:/# root@ubuntu:/# cd /tmp/ root@u ...
- Oracle案例05——ORA-12162: TNS:net service name is incorrectly specified
最近在梳理环境,发现环境真的不是一般的复杂,配置不是一般的乱,刚在梳理环境的时候发现一个库通过conn /as sysdba无法连接,具体处理过程如下: 一.错误信息 [oracle@ ~]$ sql ...
- MySQL案例01:Last_SQL_Errno: 1755 Cannot execute the current event group in the parallel mode
周五同事监控报警,有个MySQL从库复制状态异常,让我帮忙排查下,经过排查发现是MySQL5.6并行复制的一个Bug所致,具体处理过程如下: 一.错误信息 登录mysql从库服务器,检查复制状态 my ...
- C++的extern关键字
extern是一个声明,不是一个定义,A模块想应用B模块的一个函数或者变量,A模块包含B模块的头文件,并且在变量或者头文件前,加 extern,虽然编译的时候,找不到模块的定义,但是在连接的时候,会在 ...
- Python学习---重点模块之subprocess
subprocess是用来执行系统程序,查看系统的模块, 查看当前目录 第一种方法: import subprocess # subprocess会单独自己开辟一个线程,内部是多线程 # stdout ...
- easyui学习笔记3—在展开行内的增删改操作
这一篇介绍在一个展开行内进行的增删操作,如果一行很长有很多的数据,在一个展开行内进行编辑将更加方便. 1.先看引用的资源 <link rel="stylesheet" hre ...
- OC NSArray使用
#import <Foundation/Foundation.h> #import "Student.h" #pragma mark 创建一个数组 void array ...
- libevent使用event_new和不使用的两种方法
写两个简单的demo,对照一下各自的方法 #include <sys/types.h> #include <event2/event-config.h> #include &l ...
- bootstrap table footerFormatter用法 统计列求和 sum、average等
其实上一篇blog里已经贴了代码,简单解释一下吧: 1.showFooter: true,很重要,设置footer显示: $(cur_table).bootstrapTable({ url: '/et ...