当前位置: 代码迷 >> 综合 >> POJ 3207 Ikki's Story IV - Panda's Trick (2-SAT )圆内外连线问题
  详细解决方案

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

热度:47   发布时间:2023-11-23 06:38:36.0

题目来源:

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;
}

 

  相关解决方案