题意:一个圆上顺时针排放n个点,给出m条线段,每条线段要么在圆内,要么在圆外,问是否可以使这m条线段不相交。
解法:网上都是2sat的题解,但是二分图判定也可以做。m^2将所有的矛盾对连线。然后二分图判定来做。
代码:
/****************************************************
* author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
using namespace std;
#define eps 1e-8
typedef long long LL;
int judge[810];
struct edge
{
int x,y;
}edges[1000];
bool cross(int i,int j)
{
if((edges[i].x-edges[j].x)*(edges[i].y-edges[j].x)
*(edges[i].x-edges[j].y)*(edges[i].y-edges[j].y)<0)
return true;
return false;
}
int n,m;
bool rem[1000][1000];
bool dfs(int k,int t)
{
if(judge[k]!=-1)
{
if(judge[k]==t)
return true;
return false;
}
judge[k]=t;
for(int i=0;i<m;i++)
{
if(k!=i&&rem[i][k])
if(!dfs(i,1-t))
return false;
}
return true;
}
int main()
{
//freopen("a.txt", "r" , stdin);
//freopen("out.txt", "w" , stdout);
int t=0;
while(scanf("%d%d",&n,&m)!=EOF)
{
t++;
if(t==7) cout<<n<<" "<<m<<endl;
memset(rem,0,sizeof rem);
memset(judge,-1,sizeof judge);
for(int i=0;i<m;i++){
int a,b;
scanf("%d%d",&a,&b);
edges[i].x=min(a,b);
edges[i].y=max(a,b);
if(t==7&&i<30) cout<<a<<" "<<b<<endl;
}
for(int i=0;i<m;i++)
{
for(int j=i+1;j<m;j++)
{
if(cross(i,j)||cross(j,i))
rem[i][j]=1,rem[j][i]=1;//if(t==7)cout<<i<<" fdsfs "<<j<<endl;}
}
}
bool flag=1;
for(int i=0;i<m;i++)
{
if(judge[i]==-1&&!dfs(i,1))
{
flag=0;
break;
}
}
if(flag) printf("YES\n");
else printf("NO\n");
}
return 0;
}
/*
8 4
0 4
1 7
6 3
2 5
*/