HDU - 6590 Code (凸包相交)

Code

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 781 Accepted Submission(s): 287

Problem Description
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)}, with their inputs x∈Rd, and outputs y∈{−1,1}. We will try to find a function
f(x)=sign(∑di=1wi⋅xi+b)=sign(wT⋅x+b) so that f(xi)=yi,i=1,2,…,N.

w,x mentioned above are all d-dimensional vectors, i.e. w=(w1,w2,…,wd), x=(x1,x2,…,xd). To simplify the question, let w0=b, x0=1, then f(x)=sign(∑di=0wi⋅xi)=sign(wT⋅x). Therefore, finding a satisfying function f(x) is equivalent to finding a proper w.

To solve the problem, we have a algorithm, PLA(Popcorn Label Algorithm).

Accoding to PLA, we will randomly generate w.

If f(x)=sign(wT⋅x) fails to give
any element (xi,yi)∈D the right classification, i.e. f(xi)≠yi, then we will replace w with another random vector. We will do this repeatedly until all the samples ∈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 D, if PLA will end up into an infinite loop. Print Infinite loop! if so, or Successful! otherwise.

We only consider cases when d=2 for simplification.
Note: sign(x)=⎧⎩⎨−10 1 x<0x=0x>0

Input
The first line contains an integer T(1≤T≤1000), the number of test cases.
Each test case begins with a line containing a single integer n(1≤n≤100), size of the set of training samples D.
Then n lines follow, the ith of which contains three integers xi,1,xi,2,yi (−105≤xi,1,xi,2≤105, yi∈{−1,1}), indicating the ith sample (xi,yi) in D, where 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!

Source
2019 Multi-University Training Contest 1

Recommend
We have carefully selected several similar problems for you: 6623 6622 6621 6620 6619

d = 2 时,f(x) = sign(wT · x) = w0 + w1x1 + w2x2,f(x) = 0 对应于二维平面上的一
条直线,直线一侧的点取值为 1,直线另一侧的取值为 -1。故该问题等价于能否找到一条
直线将平面上的两类点分开,等价于判断这两类点分别组成的两个凸包是否相交。

所以很简单把1和-1的点分为两类,分别求凸包,然后判断凸包是否相交

#include<bits/stdc++.h>
using namespace std;
#define ll long long

ll dcmp(ll x)//用来防止结果太大爆long long 
{
	if (x > 0)  return 1;
	else if (x < 0) return -1;
	else return 0;
} 

struct point{
	point(ll a = 0,ll b = 0):x(a),y(b){}
	ll x,y;
};

ostream &operator << (ostream &out,point a)
{
	out<<a.x<<' '<<a.y<<'\n';
	return out;
} 

point operator - (point a,point b)
{
	return point(a.x - b.x,a.y - b.y);
}

ll cross(point a,point b)
{
	return (a.x * b.y - a.y * b.x);
}

ll operator * (point a,point b)
{
	return a.x * b.x + a.y * b.y;
}

bool operator == (point a,point b)
{
	if (a.x == b.x && a.y == b.y) return 1;
	return 0;
}

point basis;

bool cmp(point i,point j) 
{
	return cross(i - basis,j - basis) > 0;
}

bool onseg(point a1,point a2,point p)//点是否在线段上 
{
	if (p == a1 || p == a2) return true; 
	return cross(a1 - p,a2 - p) == 0 && (a1 -p) * (a2 - p) < 0; 
}

bool segcross(point a1,point a2,point b1,point b2)
{
	if (a1 == b1 || a1 == b2 || a2 == b1 || a2 == b2) return true;//线段端点重合 
	if (cross(a2 - a1,b2 - b1) == 0)//两条线段平行 
	{
		if (onseg(a1,a2,b1) || onseg(a1,a2,b2)) return true; //判断两条线段是否有重合 
	}
	//如果两个线段相交的话,a线段的一端与b线段两个端点相连接,所得两条线段与a线段的叉积相反 
	return (dcmp(cross(a2 - a1,b1 - a1)) * dcmp(cross(a2 - a1,b2 - a1)) <= 0)  &&  (dcmp(cross(b2 - b1,a1 - b1)) * dcmp(cross(b2 - b1,a2 - b1)) <= 0);
}

int main()
{
	ll p;
	cin>>p;
	while (p--) 
	{
		ll n,lena = 0,lenb = 0,lenp1 = 0,lenp2 = 0;
		point a[110] = {},b[110] = {},p1[110] = {},p2[110] = {},ta(1e6,1e6),tb(1e6,1e6);
		scanf("%lld",&n);
		for (ll i = 1,c;i<=n;i++)
		{
			point t;
			scanf("%lld%lld%lld",&t.x,&t.y,&c);
			if (c == 1)//正的分一类 
			{
				if (ta.x == 1e6)
				{
					ta = t;
					continue;
				}
				else
				{
					if (t.y < ta.y || (t.y == ta.y && t.x < ta.x)) swap(t,ta);//找到y最小的点,如果y相同选择x坐标最小的点 
					a[++lena] = t;
				}
			}
			else if (c == -1)//负的分一类 
			{
				if (tb.x == 1e6)
				{
					tb = t;
					continue;
				}
				else
				{
					if (t.y < tb.y || (t.y == tb.y && t.x < tb.x)) swap(t,tb);//同理 
					b[++lenb] = t;
				}
			}
		}
		///下面开始求凸包 
		basis = ta;
		sort(a+1,a+lena+1,cmp);//以basis为基准点,逆时针极角排序
		p1[++lenp1] = a[++lena] = ta;
		basis = tb;
		sort(b+1,b+lenb+1,cmp);
		p2[++lenp2] = b[++lenb] = tb;
		for (ll i = 1;i<=lena;i++)//构造a数组的凸包 
		{
			//构造凸包时新添加的线与前面一条相比都是逆时针旋转的,遇到顺时针旋转的就说明当前当前的线和原来的线都到凸包内部去了 
			while (lenp1 > 1 && (cross(a[i] - p1[lenp1],p1[lenp1] - p1[lenp1-1]) > 0) ) lenp1--;
			p1[++lenp1] = a[i];
		}
		for (ll i = 1;i<=lenb;i++)//构造b数组的凸包 
		{
			while (lenp2 > 1 && (cross(b[i] - p2[lenp2],p2[lenp2] - p2[lenp2-1]) > 0) ) lenp2--;
			p2[++lenp2] = b[i];
		}
		//下面判断凸包是否相交 
		bool flag = 1;
		if (lenp1 != 2 && lenp2 != 2)
		{
			for (ll i = 1;i<=lenp1-1;i++)//枚举端点 线段 
			{
				for (ll j = 1;j<=lenp2-1;j++)
				{
					//凸包上的线段相交 或者 线段是否一个端点一个点在另外一条线段中
					if (segcross(p1[i],p1[i+1],p2[j],p2[j+1]) || onseg(p1[i],p1[i+1],p2[j]) || onseg(p2[j],p2[j+1],p1[i]))
					{
						flag = 0;
						break;
					}
				}
				if (flag == 0) break;
			}
		}
		if (flag == 0)
		{
			printf("Infinite loop!\n");
			continue;
		}
		for (ll i = 1;i<=lenp1-1;i++)//判断点在不在凸包内部 
		{
			ll num = 0;
			for (ll j = 1;j<=lenp2-1;j++)
			{
				if (cross(p2[j+1] - p2[j],p1[i] - p2[j]) > 0) num++;//点在凸包内部,则 凸包上的点与凸包内的点的连线 与 凸包上线 的叉积一直相同 
			}
			if (num == lenp2-1)
			{
				cout<<p1[i];
				flag = 0;
				break;
			}
		}
		if (flag == 0)
		{
			printf("Infinite loop!\n");
			continue;
		}
		for (ll i = 1;i<=lenp2-1;i++)
		{
			ll num = 0;
			for (ll j = 1;j<=lenp1-1;j++)
			{
				if (cross(p1[j+1] - p1[j],p2[i] - p1[j]) > 0) num++;
			}
			if (num == lenp1-1)
			{
				flag = 0;
				break;
			}
		}
		if (flag == 0)
		{
			printf("Infinite loop!\n");
			continue;
		}
		else printf("Successful!\n");	
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值