/*************************************************************************
> Author: MentalOmega
> Mail: 965194745@qq.com
> Created Time:2017年10月13日
> function:题意说的是有n条直线把一个无限大的平面分割成了若干个区域,问每个区域有没有至少一个骑士在守卫。
这道题的直线有一个条件是No three rivers have a common point,那么就可以发现一个规律,平面数是1+直线数+交点数。
那么一开始就可以从求直线的交点的个数算出有多少个平面,然后枚举每条直线去分割平面
************************************************************************/
#include<bits/stdc++.h>
#define Vector Point
using namespace std;
int n,m;
const int MAXN = 50010;
struct Point
{
long long x,y;
}point[50010];
long long color[50010];
long long mp[5001000];
Point operator - (const Point &a,const Point &b)
{
return {a.x-b.x,a.y-b.y};
}
long long operator ^ (const Point &a,const Point &b)
{
return a.x*b.y-a.y*b.x;
}
struct Line
{
Vector v;
int a , b , c ;
}line[110];
int main()
{
if (fopen("in.txt", "r") != NULL)
{
freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
}
int t;
cin>>t;
while(t--)
{
memset(color,0,sizeof color);
memset(mp,0,sizeof mp);
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
Vector v={b,-a};
Point p={0,-c};
line[i].a = a ;
line[i].b = b ;
line[i].c = c ;
line[i].v = v;
}
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
point[i]={x,y};
}
int cnt=1;
for(int i=0;i<n;i++)//计算平面数
{
int p=0;
for(int j=i+1;j<n;j++)
{
if(line[i].v^line[j].v)
p++;
}
cnt+=p+1;
}
int top=0,botton=0;
for(int i=0;i<n;i++)
{
botton=(++top);//开始新的一轮的染色
for(int j=0;j<m;j++)
{
long long a , b , c ;
a = line[i].a ;
b = line[i].b ;
c = line[i].c ;
if( a * point[j].x + b * point[j].y + c > 0 )//这里只染直线上半部分的点
{
if(mp[color[j]]<botton)//如果这个颜色的标号是上一轮的就更新标号
color[j]=mp[color[j]]=top,top++;
else
color[j]=mp[color[j]];
}
}
}
set<long long> rec;//记录有多少种不同的颜色
for(int i=0;i<m;i++)
{
rec.insert(color[i]);
}
if(rec.size()==cnt) puts("PROTECTED");
else puts("VULNERABLE");
}
return 0;
}
下面演示一次这个过程
这里每次染的是直线的下半部分