poj3207-Ikki's Story IV - Panda's Trick

\(n\)个数字按顺序排成一圈,给出\(m\)条连线\((a,b)\),连线可以在圆内或圆外,问是否可能做到所有连线只在顶点上相交。

分析

一个好像平面图判定的题~

两条线\((a,b)\)\((c,d)\)相交的条件是\(a<c<b<d\),如果他们在圆内会相交,那么他们在圆外也会相交,也就是说,这两条线是不能同时在圆内或圆外的。一条线在圆内或圆外,有两种取值,可以看成是一个2-SAT问题。发现数据范围不大,所以直接对所有的连线两两判定一下,连边表示他们不共存就好了。注意不共存的连边是\(a\ne b\),等价于\(a\oplus b=true\)

其实这个题还可以用二分图染色做。观察上面的连边,可以发现,这里的条件都是某两条线的不共存,所以我们可以把圆内和圆外看成二分图的左边和右边,不共存的连边,然后只要判断这个图是不是一个二分图即可。

代码

2-SAT

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
using namespace std;
int read() {
    int x=0,f=1;
    char c=getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=1005;
const int maxm=maxn*maxn;
int dfn[maxn],low[maxn],id[maxn],dft=0,sta[maxn],top=0,col=0;
bool ins[maxn];
struct line {
    int x,y;
    void sort() {
        if (x>y) swap(x,y);
    }
} a[maxn];
bool cross(line &a,line &b) {
    return a.x<b.x && b.x<a.y && a.y<b.y;
}
struct edge {
    int v,nxt;
};
struct graph {
    edge e[maxm];
    int h[maxn],tot;
    graph ():tot(0) {}
    void add(int u,int v) {
        e[++tot]=(edge){v,h[u]};
        h[u]=tot;
    }
    void Tarjan(int x) {
        dfn[x]=low[x]=++dft;
        sta[++top]=x;
        ins[x]=true;
        for (int i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) if (!dfn[v]) {
            Tarjan(v);
            low[x]=min(low[x],low[v]);
        } else if (ins[v]) low[x]=min(low[x],dfn[v]);
        if (low[x]==dfn[x]) {
            ++col;
            do id[sta[top--]]=col; while (sta[top+1]!=x);
        }
        ins[x]=false;
    }
    bool run(int m) {
        for (int i=1;i<=m;++i) if (id[i]==id[i+m]) return false;
        return true;
    }
} A;
int main() {
#ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
#endif
    int n=read(),m=read();
    for (int i=1;i<=m;++i) a[i].x=read(),a[i].y=read(),a[i].sort();
    for (int i=1;i<=m;++i) for (int j=i+1;j<=m;++j) if (cross(a[i],a[j])) {
        A.add(i,j+m),A.add(j,i+m),A.add(i+m,j),A.add(j+m,i);
    }
    for (int i=1;i<=(m<<1);++i) if (!dfn[i]) A.Tarjan(i);
    puts(A.run(m)?"panda is telling the truth...":"the evil panda is lying again");
    return 0;
}

二分图染色

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
using namespace std;
int read() {
    int x=0,f=1;
    char c=getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=1005;
const int maxm=maxn*maxn;
int col[maxn];
bool flag=true;
struct line {
    int x,y;
    void sort() {
        if (x>y) swap(x,y);
    }
} a[maxn];
bool cross(line &a,line &b) {
    return a.x<b.x && b.x<a.y && a.y<b.y;
}
struct edge {
    int v,nxt;
};
struct graph {
    edge e[maxm];
    int h[maxn],tot;
    graph ():tot(0) {}
    void add(int u,int v) {
        e[++tot]=(edge){v,h[u]};
        h[u]=tot;
    }
    bool dye(int x,int c) {
        col[x]=c;
        for (int i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) {
            if (col[v]==(c^1)) continue;
            if (col[v]==c) return false;
            if (!dye(v,c^1)) return false;
        } 
        return true;
    }
} A;
int main() {
#ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
#endif
    int n=read(),m=read();
    for (int i=1;i<=m;++i) a[i].x=read(),a[i].y=read(),a[i].sort();
    for (int i=1;i<=m;++i) for (int j=i+1;j<=m;++j) if (cross(a[i],a[j])) A.add(i,j),A.add(j,i);
    for (int i=1;i<=m;++i) if (!col[i] && !A.dye(i,2)) {
        flag=false;
        break;
    }
    puts(flag?"panda is telling the truth...":"the evil panda is lying again");
    return 0;
}

转载于:https://www.cnblogs.com/owenyu/p/6741754.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值