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. C语言实现整数数组的逆置算法

    读入100个整数到一个数组中,写出实现该数组进行逆置的算法. 方法一: 假设100个整数读入到数组a中,算法f1的思想是分别从数组两端依次将对应数进行交换,即a[i]与a[100 - i - 1]进行 ...

  2. Java 之初(1)

    省赛结束之后有相当长一段空闲时间,于是就想先提前自学一点Java语言的知识,在这里纪录一下学习过程,希望能给自学Java的同学提供一点小帮助!(当然,也能方便我以后的复习用^_^) 在学习过程中有什么 ...

  3. MFC string char cstring 类型转换

    在Unicode环境下用以下转换: CString z_strCurtTime = _T(""); // 获取当前时间 CTime z_tCurTime = CTime::GetC ...

  4. shiro(java安全框架)

    shiro(java安全框架) 以下都是综合之前的人加上自己的一些小总结 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码学和会话管理.使用Shiro的易于理解的A ...

  5. LESS嵌套中的Mixins和classes

    less的嵌套规则对于有效组织你的css代码有较好的作用.其中使用mixin或者class都可以作为被嵌套的实体,但是二者还是有区别的: mixin必须由.name+(){}的pattern来定义,而 ...

  6. 一个典型的后台软件系统的设计复盘——(三)打通任督二脉-context

    武侠小说练功讲究打通任督二脉.程序设计练到一定程度也讲究打通任督二脉.好奇心强的同学可以搜搜“打通任督二脉有什么感觉”. spring的任督二脉ApplicationContext 最经典的任督二脉莫 ...

  7. Windows 编译 MQTT C++ Client

    MQTT MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分.该协议支持所有平台,几乎可 ...

  8. 一个老IT产品管理者对于产品经理工作的经验总结

    一个老IT产品管理者对于产品经理工作的经验总结 1. 任何行业,包括IT行业,所谓产品管理.产品经理,其核心应该是企业产品管理制度,也就是说,只有企业存在相应的.合理的产品管理体系和制度,产品管理.产 ...

  9. FireFox浏览器Flash&视频下载工具推荐

    介绍 两款扩展组件:Flash and Video Download & Flash Video Downloader 一起使用,各有优缺点. Flash and Video Download ...

  10. 在giuhub上演示自己的项目

    首先在github上建立项目,然后git clone; 然后切换分支到 git checkout gh-pages 最后提交代码到这个分支上,访问地址:[github用户名].github.io/[项 ...