HDU 6590 Code (求两个凸包是否相离)

题面

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!

题目链接

HDU 6590

参考

2019 Multi-University Training Contest 1标程(标程的安德鲁求凸包写错了,没有对点进行排序且把上下凸包求错了)

UVALive 7281 Saint John Festival (求凸包+判断点是否在凸包内(O(logn)复杂度))

UVa 10256 (判断两个凸包相离) The Great Divide

题意

求一个二维的W向量(w_{1},w_{2}),使得对于每个x向量(x_{1},x_{2}),都有w_{1}x_{1}+w_{2}x_{2}+b>0w_{1}x_{1}+w_{2}x_{2}+b<0

分析

根据线性规划有直线Ax+By+b=0,将x向量看成一个点x_{1}为横坐标,x_{2}为纵坐标。

w1为A,w2为B,则w_{1}x_{1}+w_{2}x_{2}+b>0(x_{1},x_{2})在直线一侧,则w_{1}x_{1}+w_{2}x_{2}+b<0(x_{1},x_{2})在直线另一侧。

(可以同时改变w1,w2,b的正负号,来更改(x_{1},x_{2})的直线的上下位置)

则根据y的值,将(x_{1},x_{2})分成两个点集,如果要Successful! 则存在一条直线能将两个点集分隔开。

即两个点集的最大凸包相离。

判断两个凸包相离

  1. 任何一个凸包的任何一个顶点不能在另一个凸包的内部或者边界上。
  2. 两个凸包的任意两边不能相交。

第一次写这个题,将点集的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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值