POJ 3207 Ikki's Story IV - Panda's Trick (2-SAT )圆内外连线问题

题目来源:

http://poj.org/problem?id=3207

题意:
平面上有一个圆,圆上有n个点(分别编号0-n-1,按顺序在圆上排列),现在要对着n个点连接m条线,这m条线的两个端点已经给出了(但是没说这些先是连内圈还是连外圈),这个线可以从圆内连或从圆外连.且任意一个点最多只作为一条线的端点.要求任意两条线不相交,问你是否可能?

分析:

        由于题目中需要连接的边都确定给出了,我们可以根据任意两线i与j的端点推断出当i与j同时在圆内或圆外是否一定会相交。

        如果边i与j同在圆的一侧必定相交,那么边i与边j必然一个在圆内,一个在圆外,所以有如下结论:

        i在圆内或j在圆内 且 i在圆外或j在圆外 (想想为什么)

        那么如何判断边i(ui,vi) 与 j(uj,vj) 在圆同一侧时一定会相交呢?

        由于这里端点是在圆上的,所以如果j边的两点中,一点处于i边两端点的ui顺时针走向vi的圆弧内,一点处于i边两端点的vi顺时针走向ui的圆弧内,那么i与j在圆同一侧时一定相交。否则一定不想交。

代码:

#include<iostream>
#include<cstring>
#include<stack>
#include<iomanip>
#include<cmath>
#include<queue>
#include<algorithm>
#include<stdio.h>
using namespace std;
# define ll long long
const int maxn=1010;
const int maxm=410000;
int op[maxn],vis[maxn],low[maxn],dfn[maxn];
int pt[maxn],stk[maxn],color[maxn],pos[maxn],deg[maxn];
vector<int>vc[maxm],vc2[maxm];

struct node
{
  int x;
  int y;
}p[maxn],hate[maxn],like[maxn],s1,s2,tmp;
int a,b,dis[maxn],slen;
int x[maxn],y[maxn];
int dist(node aa,node bb)
{
  return abs(aa.x-bb.x)+abs(aa.y-bb.y);
}
int n,m,sig,cnt,tot,cont;
void add(int x,int y){
    vc[x].push_back(y);
}
void top(){
    memset(pt,0,sizeof(pt));
    queue<int>s;
    for(int i=1;i<=sig;i++){
        if(deg[i]==0) s.push(i);
    }
    while(!s.empty()){
        int u=s.front();
        if(pt[u]==0){
            pt[u]=1;
            pt[pos[u]]=2;
        }
        s.pop();
        for(int i=0;i<vc2[u].size();i++){
            int v=vc2[u][i];
            deg[v]--;
            if(deg[v]==0) s.push(v);
        }
    }
    cont=0;
    for(int i=1;i<=n;i++) {
        if(pt[color[i]]==1) op[cont++]=i;
    }
}
void tarjan(int u)
{
    vis[u]=1;
    dfn[u]=low[u]=cnt++;
    stk[++tot]=u;
    for(int i=0;i<vc[u].size();i++){
        int v=vc[u][i];
        if(vis[v]==0) tarjan(v);
        if(vis[v]==1) low[u]=min(low[u],low[v]);
    }
    if(low[u]==dfn[u]) {
        sig++;
        do{
            vis[stk[tot]]=-1;
            color[stk[tot]]=sig;
        }while(stk[tot--]!=u);
    }
}
void init(){
    sig=0;cnt=1;tot=-1;
    memset(deg,0,sizeof(deg));
    memset(stk,0,sizeof(stk));
    memset(dfn,0,sizeof(dfn));
    memset(vis,0,sizeof(vis));
    memset(color,0,sizeof(color));
    for(int i=0;i<maxn;i++) {
        vc[i].clear();
        vc2[i].clear();
    }
}
int solve(){
    for(int i=1;i<=m*2;i++) {
        if(vis[i]==0) tarjan(i);
    }
    for(int i=1;i<=m;i++) {
        if(color[i]==color[i+m]) return 0;
        pos[color[i]]=color[i+m];
        pos[color[i+m]]=color[i];
    }
    for(int i=1;i<=m*2;i++){
        for(int j=0;j<vc[i].size();j++){
            int v=vc[i][j];
            if(color[i]!=color[v]){
                deg[color[i]]++;
                vc2[color[v]].push_back(color[i]);
            }
        }
    }
    top();
    return 1;
}
bool judge(int mid)
{
    init();
    for(int i=0;i<n;i++)
    {
        for(int j=i+1;j<n;j++)
        {
            if(dis[i]+dis[j]>mid)
            {
                add(i,j+n);
                add(j,i+n);
            }
            if(dis[i+n]+dis[j+n]>mid)
            {
                add(i+n,j);
                add(j+n,i);
            }
            if(dis[i]+slen+dis[j+n]>mid)
            {
                add(i,j);
                add(j+n,i+n);
            }
            if(dis[i+n]+slen+dis[j]>mid)
            {
                add(i+n,j+n);
                add(j,i);
            }
        }
    }
    for(int i=0;i<a;i++)
    {
        add(hate[i].x,hate[i].y+n);
        add(hate[i].y+n,hate[i].x);
        add(hate[i].x+n,hate[i].y);
        add(hate[i].y,hate[i].x+n);
    }
    for(int i=0;i<b;i++)
    {
        add(like[i].x,like[i].y);
        add(like[i].y,like[i].x);
        add(like[i].x+n,like[i].y+n);
        add(like[i].y+n,like[i].x+n);
    }
    return solve();
}
int main()
{
    scanf("%d%d",&n,&m);
    init();
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x[i],&y[i]);
        x[i]++;
        y[i]++;
        if(x[i]>y[i])
        swap(x[i],y[i]);
    }
    for(int i=1;i<=m;i++)
        for(int j=i+1;j<=m;j++)
            if((x[i]<=x[j]&&y[i]>=x[j]&&y[i]<=y[j])||(x[i]>=x[j]&&x[i]<=y[j]&&y[i]>=y[j]))
            {
                add(i,j+m);
                add(j,i+m);
                add(i+m,j);
                add(j+m,i);
            }
    int ans=solve();
    if(ans)
        printf("panda is telling the truth...\n");
    else printf("the evil panda is lying again\n");
    return 0;
}

 

上一篇:SpringMVC 学习笔记(拦截器的配置))


下一篇:【CentOS 6.5】 U盘安装以及桌面空白问题