D. Limak and Shooting Points 計算幾何+模擬

D. Limak and Shooting Points
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Bearland is a dangerous place. Limak can’t travel on foot. Instead, he has k magic teleportation stones. Each stone can be used at most once. The i-th stone allows to teleport to a point (axi, ayi). Limak can use stones in any order.

There are n monsters in Bearland. The i-th of them stands at (mxi, myi).

The given k + n points are pairwise distinct.

After each teleportation, Limak can shoot an arrow in some direction. An arrow will hit the first monster in the chosen direction. Then, both an arrow and a monster disappear. It’s dangerous to stay in one place for long, so Limak can shoot only one arrow from one place.

A monster should be afraid if it’s possible that Limak will hit it. How many monsters should be afraid of Limak?

Input

The first line of the input contains two integers k and n (1 ≤ k ≤ 71 ≤ n ≤ 1000) — the number of stones and the number of monsters.

The i-th of following k lines contains two integers axi and ayi ( - 109 ≤ axi, ayi ≤ 109) — coordinates to which Limak can teleport using the i-th stone.

The i-th of last n lines contains two integers mxi and myi ( - 109 ≤ mxi, myi ≤ 109) — coordinates of the i-th monster.

The given k + n points are pairwise distinct.

Output

Print the number of monsters which should be afraid of Limak.

Examples
input
2 4
-2 -1
4 5
4 2
2 1
4 -1
1 -1
output
3
input
3 8
10 20
0 0
20 40
300 600
30 60
170 340
50 100
28 56
90 180
-4 -8
-1 -2
output
5
Note

In the first sample, there are two stones and four monsters. Stones allow to teleport to points ( - 2,  - 1) and (4, 5), marked blue in the drawing below. Monsters are at (4, 2)(2, 1)(4,  - 1) and (1,  - 1), marked red. A monster at (4,  - 1) shouldn't be afraid because it's impossible that Limak will hit it with an arrow. Other three monsters can be hit and thus the answer is 3.

In the second sample, five monsters should be afraid. Safe monsters are those at (300, 600)(170, 340) and (90, 180).


——————————————————————

題意:有k個射擊點,n只怪獸,每個射擊點只能射擊一次,且只能射擊一條直線上的第一個沒有死亡的怪獸,有多多少隻怪獸是有可能會被打死的

題解:可以發現,如果開槍的順序被確定,且都以打死一隻怪獸爲目標,那麼這隻怪獸可不可以被打死是可以模擬出來的(具體見代碼)

發現k很小,可以用k!的複雜度來枚舉所有的開槍順序

然後枚舉一個怪獸,但是發現我們還要枚舉射擊點和怪獸之間的怪獸  時間複雜度O(k!*n*n) 發現會TLE

預處理mp[i][j]表示第i個射擊點和第j只怪獸爲端點的線段間有哪些怪獸

時間複雜度優化到O(k*n*n+k!*n)


三點共線的判定:

判斷A,B,C三點共線,則AB×BC=0

若B爲中間點  則  AB·AC>0 CB·CA>0

後面一個點積的運用可以直接暴力判,這樣方便一些

我傻。。代碼裏就暴力判了


#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#include<algorithm>
#include<cstring>
#define For(i,j,k)	for(ll i=j;i<=k;++i)
#define Dow(i,j,k)	for(ll i=k;i>=j;--i)
#define ll long long
using namespace std;
inline ll read()
{
	ll t=0,f=1;char c=getchar();
	while(c==' '||c=='\n')	c=getchar();
	if(c=='-')	f=-1,c=getchar();
	while(c<='9'&&c>='0')	t=t*10+c-48,c=getchar();
	return t*f;
}
struct poi
{
	ll x,y;
} st[10],ms[2001];
ll tim,k,n,gg[2001],que[10],alr,ans;
vector<ll> mp[10][1101];
bool vis[10];
ll operator *(const poi &x,const poi &y){return x.x*y.y-x.y*y.x;}
poi operator -(const poi &x,const poi &y){static poi tmp;tmp.x=x.x-y.x;tmp.y=x.y-y.y;return tmp;}
ll operator ^(const poi &x,const poi &y){return x.x*y.x+x.y*y.y;}
inline bool check(const poi &x,const poi &a,const poi &b)
{
	if((x-a)*(x-b)!=0)	return 0;
	if(a.y==b.y)	return (x.x)<max(a.x,b.x)&&(x.x)>min(a.x,b.x);
		else return (x.y)<max(a.y,b.y)&&(x.y)>min(a.y,b.y);
}
inline bool kill(ll x)
{
	alr++;	
	if(alr==k+1)	return 0;
	if(mp[que[alr]][x].empty())	{gg[x]=tim;return 1;}
	ll gd=alr;
	for(ll i=0;i<mp[que[gd]][x].size();++i)
	{
		ll t=mp[que[gd]][x][i];
		if(gg[t]!=tim)	if(!kill(t))	return 0;
	}
	gg[x]=tim;return 1;
}
inline bool dfs(ll to,ll x)
{
	if(x==k+1)	{alr=0;tim++;return kill(to);}
	bool flag=0;
	For(i,1,k)
	{
		if(!vis[i])
		{
			vis[i]=1;que[x]=i;
			flag|=dfs(to,x+1);
			vis[i]=0;
			if(flag)	return 1;
		}
	}
	return flag;
}
int  main()
{
	k=read();n=read();
	For(i,1,k)	st[i].x=read(),st[i].y=read();
	For(i,1,n)	ms[i].x=read(),ms[i].y=read();
	For(i,1,k)
		For(j,1,n)
		{
			For(k,1,n)
				if(k!=j&&check(ms[k],st[i],ms[j]))	mp[i][j].push_back(k);
		}
	For(i,1,n)	
	{
		memset(vis,0,sizeof vis);
		if(dfs(i,1))	ans++;	
	}
	cout<<ans<<endl;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章