题面
After returning with honour from ICPC(International Cat Programming Contest) World Finals, Tom decides to say goodbye to ICPC and start a new period of life. He quickly gets interested in AI.
In the subject of Machine Learning, there is a classical classification model called perceptron, defined as follows:
Assuming we get a set of training samples: D={(x1,y1),(x2,y2),...,(xN,yN)}D={(x1,y1),(x2,y2),...,(xN,yN)} , with their inputs x∈Rdx∈Rd , and outputs y∈{−1,1}y∈{−1,1} . We will try to find a function
f(x)=sign(∑di=1wi⋅xi+b)=sign(wT⋅x+b)f(x)=sign(∑i=1dwi⋅xi+b)=sign(wT⋅x+b) so that f(xi)=yi,i=1,2,...,Nf(xi)=yi,i=1,2,...,N .
w,xw,x mentioned above are all dd -dimensional vectors, i.e. w=(w1,w2,...,wd)w=(w1,w2,...,wd) , x=(x1,x2,...,xd)x=(x1,x2,...,xd) . To simplify the question, let w0=bw0=b , x0=1x0=1 , then f(x)=sign(∑di=0wi⋅xi)=sign(wT⋅x)f(x)=sign(∑i=0dwi⋅xi)=sign(wT⋅x) . Therefore, finding a satisfying function f(x)f(x) is equivalent to finding a proper ww .
To solve the problem, we have a algorithm, PLA(Popcorn Label Algorithm).
Accoding to PLA, we will randomly generate ww .
If f(x)=sign(wT⋅x)f(x)=sign(wT⋅x) fails to give
any element (xi,yi)∈D(xi,yi)∈D the right classification, i.e. f(xi)≠yif(xi)≠yi , then we will replace ww with another random vector. We will do this repeatedly until all the samples ∈D∈D are correctly classified.
As a former-JBer, Tom excels in programming and quickly wrote the pseudocode of PLA.
w := a random vector
while true do
flag:=true
for i:=1 to N do
if f(x[ i ]) != y[ i ] then
flag:=false
break
if flag then
break
else
w := a random vector
return w
But Tom found that, in some occasions, PLA will end up into an infinite loop, which confuses him a lot. You are required to help Tom determine, when performed on a given sample set DD , if PLA will end up into an infinite loop. Print Infinite loop! if so, or Successful! otherwise.
We only consider cases when d=2d=2 for simplification.
Note: sign(x)=⎧⎩⎨−10 1 x<0x=0x>0sign(x)={−1x<00 x=01 x>0
Input
The first line contains an integer T(1≤T≤1000)T(1≤T≤1000) , the number of test cases.
Each test case begins with a line containing a single integer n(1≤n≤100)n(1≤n≤100) , size of the set of training samples DD .
Then nn lines follow, the ii th of which contains three integers xi,1,xi,2,yixi,1,xi,2,yi (−105≤xi,1,xi,2≤105,(−105≤xi,1,xi,2≤105, yi∈{−1,1})yi∈{−1,1}) , indicating the ii th sample (xi,yi)(xi,yi) in DD , where xi=(xi,1,xi,2)xi=(xi,1,xi,2) .
Output
For each test case, output a single line containing the answer: “Infinite loop!” or “Successful!”.
Sample Input
3
2
1 1 1
2 0 -1
4
0 0 1
2 0 -1
1 1 1
1 -1 -1
6
0 0 1
2 0 -1
1 1 1
1 -1 -1
1 0 1
0 1 -1
Sample Output
Successful!
Successful!
Infinite loop!
题目链接
参考
2019 Multi-University Training Contest 1标程(标程的安德鲁求凸包写错了,没有对点进行排序且把上下凸包求错了)
UVALive 7281 Saint John Festival (求凸包+判断点是否在凸包内(O(logn)复杂度))
UVa 10256 (判断两个凸包相离) The Great Divide
题意
求一个二维的W向量,使得对于每个x向量
,都有
或
分析
根据线性规划有直线Ax+By+b=0,将x向量看成一个点为横坐标,
为纵坐标。
w1为A,w2为B,则的
在直线一侧,则
的
在直线另一侧。
(可以同时改变w1,w2,b的正负号,来更改的直线的上下位置)
则根据y的值,将分成两个点集,如果要Successful! 则存在一条直线能将两个点集分隔开。
即两个点集的最大凸包相离。
判断两个凸包相离
- 任何一个凸包的任何一个顶点不能在另一个凸包的内部或者边界上。
- 两个凸包的任意两边不能相交。
第一次写这个题,将点集的vector数组设成全局变量。对于每组数据,先清空vector。TLE……
将vector放入函数中,可以节省清空vector的时间。
以空间换时间
程序
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
const double eps=1e-10;
struct Node
{
double x1,x2,y;
}node[105];
int cnt;
int sgn(double x)
{
if(fabs(x)<eps) return 0;
return x<0?-1:1;
}
struct Point
{
double x,y;
Point(){}
Point(double x,double y):x(x),y(y){}
bool operator==(const Point &B)const
{
return sgn(x-B.x)==0 && sgn(y-B.y)==0;
}
bool operator<(const Point &B)const
{
return sgn(x-B.x)<0 || (sgn(x-B.x)==0 && sgn(y-B.y)<0);
}
};
typedef Point Vector;
Vector operator-(Point A,Point B)
{
return Vector(A.x-B.x,A.y-B.y);
}
double Cross(Vector A,Vector B)
{
return A.x*B.y-A.y*B.x;
}
double operator*(Point a, Point b) {
return a.x * b.y - a.y * b.x;
}
long long operator^(Point a, Point b) {
return a.x* b.x + a.y * b.y;
}
double det(Point a, Point b, Point c) {
return (b - a) * (c - a);
}
struct L {
Point a, b;
L () {}
L (Point x, Point y) {
a=Point(x.x,x.y),b = Point(y.x,y.y);
}
};
bool onSeg(Point p, L s) {
return sgn(det(p, s.a, s.b)) == 0 && sgn((s.a - p) ^ (s.b - p)) <= 0;
}
bool SegmentIntersection(L l1, L l2) {
double c1 = det(l1.a, l1.b, l2.a), c2 = det(l1.a, l1.b, l2.b);
double c3 = det(l2.a, l2.b, l1.a), c4 = det(l2.a, l2.b, l1.b);
if (sgn(c1) * sgn(c2) < 0 && sgn(c3) * sgn(c4) < 0) return true;
if (sgn(c1) == 0 && onSeg(l2.a, l1)) return true;
if (sgn(c2) == 0 && onSeg(l2.b, l1)) return true;
if (sgn(c3) == 0 && onSeg(l1.a, l2)) return true;
if (sgn(c4) == 0 && onSeg(l1.b, l2)) return true;
return false;
}
int ConvexHull(vector<Point>p,int n,vector<Point>&ch)//安德鲁求凸包
{
sort(p.begin(),p.end());
n=unique(p.begin(),p.end())-p.begin();
int m=0;
for(int i=0;i<n;i++)
{
while(m>1 && Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)
{
ch.pop_back();
m--;
}
ch.push_back(p[i]);
m++;
}
int k=m;
for(int i=n-2;i>=0;i--)
{
while(m>k && Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)
{
ch.pop_back();
m--;
}
ch.push_back(p[i]);
m++;
}
if(n>1)
{
m--;
ch.pop_back();
}
return m;
}
bool PointInPolygon(Point A,vector<Point>p)//判断点在凸包内模板 O(logn)
{
int n=p.size();
int l=1,r=n-2,mid;
while(l<=r)
{
mid=(l+r)>>1;
double a1=Cross(p[mid]-p[0],A-p[0]);
double a2=Cross(p[mid+1]-p[0],A-p[0]);
if(a1>=0&&a2<=0)
{
if(Cross(p[mid+1]-p[mid],A-p[mid])>=0)return true;
return false;
}
else if(a1<0)
r=mid-1;
else
l=mid+1;
}
return false;
}
bool ConvexHullDivide(vector<Point> p1, vector<Point> p2)/**判断两个凸包是否相交**/
{
for (int i = 0; i < p1.size(); i++)
if (PointInPolygon(p1[i], p2))/**判断p1的点是否在p2中**/
return false;
for (int i = 0; i < p2.size(); i++)
if (PointInPolygon(p2[i], p1))/**判断p2的点是否在p1中**/
return false;
for (int i = 0; i < p1.size(); i++)
for (int j = 0; j < p2.size(); j++)/**判断两个凸包的边是否相交**/
if (SegmentIntersection(L(p1[i], p1[(i + 1) % p1.size()]), L(p2[j], p2[(j + 1) % p2.size()])))
return false;
return true;/**两个凸包相离**/
}
const int maxn= 50000+500 ;
bool work()/**判断两个点集是否相交**/
{
vector<Point>ori_1,ori_2;
vector<Point>c1,c2;
for(int i=0;i<cnt;i++)
{
double x1=node[i].x1;
double x2=node[i].x2;
double y=node[i].y;
if(sgn(y-1.0)==0)
ori_1.push_back(Point(x1,x2));
else
ori_2.push_back(Point(x1,x2));
}
ConvexHull(ori_1,ori_1.size(),c1);
ConvexHull(ori_2,ori_2.size(),c2);
bool answer;
if(c1.size()==0||c2.size()==0)
answer=true;
else
{
if(!ConvexHullDivide(c1,c2))
answer=false;
}
return answer;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
cnt=0;
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
double x1,x2,y;
scanf("%lf%lf%lf",&node[cnt].x1,&node[cnt].x2,&node[cnt].y);
cnt++;
}
if(work())
printf("Successful!\n");
else
printf("Infinite loop!\n");
}
return 0;
}
PS
提供一组可以hack掉2019 Multi-University Training Contest 1标程的样例
1
11
3 0 -1
5 1 -1
5 -1 -1
4 2 -1
3 -2 -1
0 -1 -1
1 2 -1
1 -2 -1
0 1 -1
2 0 -1
0 0 1
答案应该是Infinite loop! 标程是Successful!
2019年07月27日 10:27:23