题意:给出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;
}