竞赛题解 - 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 ...
随机推荐
- 关于moucedown 的3种触发方式
与 click 事件不同 mousedown 按下鼠标就可以触发 click 只能用鼠标左键触发, 而mousedown 可以由单击.中键.或右击 触发 根据对event.which 的判断,可以 ...
- Visual Studio Code调试electron主进程
Visual Studio Code调试electron主进程 作者: jekkay 分类: electron 发布时间: 2017-06-11 14:56 一·概述 此文原出自[水滴石]: htt ...
- Windows 实用小工具
超实用的Windows工具 ====================================================================================== ...
- 如果使用没有提供选项值的 SqlDependency,必须先调用 SqlDependency.Start(),然后才能执行添加到 SqlDependency 实例中的命令
如标题错误,解决办法及出现错误情况,见图片 出现如图错误
- mongodb---js脚本操作速记
之前写一些mongodb的同步或操作程序,往往使用perl,甚至c实现,这样程序很繁琐,而且逻辑不好控制,甚至一些功能和命令什么的,在这些语言的mongo驱动中就没有实现.后来发现mongodb 的s ...
- C语言编译器,写给萌新们看看。
就我已经经历过的大学课程,仿佛每一门计算机的专业课程的开头,都是在介绍计算机发展的历史,和大名鼎鼎的冯诺依曼结构. 譬如C语言,比较水的计算机导论,c++,数据结构,计算机组成原理,甚至是Linux实 ...
- Dom4j的一个小例子,用于解析xml文件的元素获取方式
import java.io.File; import java.io.IOException; import javax.xml.parsers.ParserConfigurationExcepti ...
- Eclipse环境下配置Tomcat,并且把项目部署到Tomcat服务器上
一 配置Tomcat 1.打开Eclipse,单击"Window"菜单,选择下方的"Preferences". 2.单击"Server"选项 ...
- JAVA串口开发帮助类分享-及写在马年末
摘要: 在系统集成开发过程中,存在着各式的传输途径,其中串口经常因其安全性高获得了数据安全传输的重用,通过串口传输可以从硬件上保证数据传输的单向性,这是其它介质所不具备的物理条件.下面我就串口java ...
- Vue、PHP、Bootstrap联手打造简单数据管理表格
这是一个用Vue.Bootstrap和PHP一起写的小实例,回顾总结了一下之前学习的知识,顺带添加点学习乐趣. 先上效果图: 用到的知识有:Vue数据绑定及组件.Bootstrap界面.PHP-AJA ...