题意:给出m个射击位置,和n个静止的射击目标,在每个射击位置只能开一枪,问有多少位置是可能被射击到的。

题解:

对每个目标单独独立判断是否可能被射击到即可,判断方法是dfs,关键是dfs的方法。

找到合适高效的dfs是关键,我就在这里跪倒了,太菜了,最后学习了codeforces里大佬的解法,又一次跪服。。。

首先,以开枪顺序为切入点,干掉一个目标最多开m枪,而且开枪的顺序也就是m的全排列。但如果你又想到:每个射击点可以射击的目标有很多种,还需要搜时,就走入误区了。

我们的搜索原则应是:只要把一种方案或者说是正解搜出来就行,也就是说,如果存在正解,搜索方式不会漏掉就行,举个例子。

目标是a b c d e f ......           射击点是1 2 3 4 5 6 7

假设当前判断的是a是否危险,同时假设正解是a被5干掉,且挡在a和5之间的有目标 b,c,d

假设射击点 2,3,4是为了干掉b,7是为了干掉c,6是为了干掉d,那么正解的开枪顺序为5 2 3 4 6 7 

注意 2 3 4 为了干掉 b,因为是3枪,肯定不是直接干掉,所以又产生干掉 b的子问题。

就是说,正解是5 2 3 4 6 7 ,5 2 4 3 6 7 ,5 3 2 4 6 7 .......中的一种,但是由于我们是枚举的全排列,也就是说,一定会搜出来正解。

综上,搜素方式就是,枚举全排列,(可以理解为开枪顺序),判断这一顺序是否会使目标***掉。

确定完顺序后,每遇到一个挡着的目标,(也就是需要先干掉的目标),就从射击点中按顺序取下一个没开枪的射击点,由于每到一层,就开一枪,所以判断一个顺序是否满足的复杂度是O(m)的,总复杂度就是O(n*m*m!)。

细节还需看程序细细体会。

代码:

#include<bits/stdc++.h>
#define N 10010
#define INF 0x3f3f3f3f
#define LL long long
#define pb push_back
#define cl clear
#define si size
#define lb lowwer_bound
#define eps 1e-8
const LL P=1e9+7;
#define IO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
int dcmp(double x){if (fabs(x)<eps)return 0;else return x<0?-1:1;}

struct Point
{
    double x,y;
    bool operator < (const Point &a)const
    {return dcmp(x-a.x)<0 || (dcmp(x-a.x)==0 && dcmp(y-a.y)<0);}
    Point(double x=0,double y=0):x(x),y(y){ }
    void read(){scanf("%lf%lf",&x,&y);}
};
typedef Point Vector;

Vector operator + (Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y);}
Vector operator - (Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
bool operator == (Vector a,Vector b){return a.x==b.x && a.y==b.y;}
double Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}  //点积
double Length(Vector a){return sqrt(Dot(a,a));}
double Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;} //叉积

int f[N][8][8];
int n,m,w;
Point a[N],b[8];
int g[8],id[N];int ti,tot;
vector<int>xx;

bool isPointOnSegment(Point P,Point A,Point B)
{
    return dcmp(Cross(A-P,B-P))==0 && dcmp(Dot(A-P,B-P))<=0;  // 不包含端点时为 <0
}

bool dfs(int x)
{
    if (tot>m) return false;
    int now=g[tot++];
    if (f[x][now][0]>m) return false;
    for (int i=1;i<=f[x][now][0];i++){
        if (id[f[x][now][i]]!=ti){
            if (!dfs(f[x][now][i])) return false;
        }
    }
    id[x]=ti;
    return true;
}

int main()
{
    IO
	cin>>m>>n;
	for (int i=1;i<=m;i++) cin>>b[i].x>>b[i].y;
	for (int i=1;i<=n;i++) cin>>a[i].x>>a[i].y;

	for (int i=1;i<=n;i++)
	for (int j=i+1;j<=n;j++)
	{
		for(int k=1;k<=m;k++)
		{
			if (isPointOnSegment(a[j],a[i],b[k]))
			{
				if (f[i][k][0]<m-1)f[i][k][++f[i][k][0]]=j;else
					f[i][k][0]=10;
			}
			if (isPointOnSegment(a[i],a[j],b[k]))
			{
				if (f[j][k][0]<m-1)f[j][k][++f[j][k][0]]=i;else
					f[j][k][0]=10;
			}
		}
	}

	int danger=0;
	for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++) g[j]=j;
        do{
            ++ti; tot=1;
            if (dfs(i)) {danger++;break;}
        } while(next_permutation(g+1,g+m+1));
	}
    cout<<danger;
    return 0;
}