zoukankan      html  css  js  c++  java
  • 【CF698D】Limak and Shooting Points(DFS)

    点此看题面

    • 平面上有(k)个人和(n)个怪物,规定一个人一次只能向某个方向射死第一个怪物。
    • 求有多少怪物可能被射死。
    • (kle 7,nle10^3)

    暴力全排列+顺序指定

    对于一个怪物,我们直接枚举人的全排列。

    我们假设由第一个人射死了这个怪物,那么之后的人就要为他扫清障碍,方便起见规定之后的人从第一个人到这个怪物之间的第一个怪物开始依次扫清。

    然而,第二个人若想扫清第一个障碍,中间可能还会存在其他障碍,这相当于是一个递归的过程,就由第三个人开始为他先扫清障碍。

    具体实现中只要定义一个(Check(x))函数,并在此之外设立一个全局变量(nw)表示当前要让(nw)射死(x),然后递归调用就可以解决了。

    因为我们枚举了全排列,所以这样强定顺序是毫无问题的。

    最好现在一开始预处理出每个人和每个怪物之间所有的障碍怪物,能够提高代码效率。

    代码:(O(kn^2+nkcdot k!))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define K 7
    #define N 1000
    using namespace std;
    int k,n,id[K+5];vector<int> P[K+5][N+5];
    I int gcd(CI x,CI y) {return y?gcd(y,x%y):x;}
    struct P
    {
    	int x,y;I P(CI a=0,CI b=0):x(a),y(b){}
    	I long long L2() {return 1LL*x*x+1LL*y*y;}
    	I P S() {RI d=gcd(abs(x),abs(y))*(x?(x>0?1:-1):(y>0?1:-1));return P(x/d,y/d);}
    	I P operator - (Con P& o) Con {return P(x-o.x,y-o.y);}
    	I bool operator < (Con P& o) Con {return x^o.x?x<o.x:y<o.y;}
    	I bool operator == (Con P& o) Con {return x==o.x&&y==o.y;}
    }s[K+5],p[N+5];
    int nw,vis[N+5];I bool Check(CI x)//检验nw能否射死x
    {
    	if(nw>k) return 0;RI o=id[nw];vector<int>::iterator it;
    	for(it=P[o][x].begin();it!=P[o][x].end();++it) if(!vis[*it]&&(++nw,!Check(*it))) return 0;//把中间的障碍全部清除
    	return vis[x]=1;//标记被杀死
    }
    int op;I bool cmp(CI x,CI y) {return (p[x]<p[y])==op;}
    int main()
    {
    	RI i,j,u;for(scanf("%d%d",&k,&n),i=1;i<=k;++i) scanf("%d%d",&s[i].x,&s[i].y);
    	for(i=1;i<=n;++i) scanf("%d%d",&p[i].x,&p[i].y);
    	for(i=1;i<=k;++i) for(j=1;j<=n;op=s[i]<p[j],sort(P[i][j].begin(),P[i][j].end(),cmp),++j)//枚举人i和怪物j,求出之间的怪物
    		for(u=1;u<=n;++u) j^u&&(s[i]-p[j]).S()==(s[i]-p[u]).S()&&(s[i]<p[u])==(p[u]<p[j])&&(P[i][j].push_back(u),0);//枚举怪物判断是否在它们中间
    	RI fg,t=0;for(i=1;i<=n;t+=fg,++i) {for(j=1;j<=k;++j) id[j]=j;
    		do {memset(vis,0,sizeof(vis)),nw=1,fg=Check(i);} W(!fg&&next_permutation(id+1,id+k+1));}//暴力全排列
    	return printf("%d
    ",t),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    hdu 6702 ^&^ 位运算
    hdu 6709 Fishing Master 贪心
    hdu 6704 K-th occurrence 二分 ST表 后缀数组 主席树
    hdu 1423 Greatest Common Increasing Subsequence 最长公共上升子序列 LCIS
    hdu 5909 Tree Cutting FWT
    luogu P1588 丢失的牛 宽搜
    luogu P1003 铺地毯
    luogu P1104 生日
    luogu P1094 纪念品分组
    luogu P1093 奖学金
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF698D.html
Copyright © 2011-2022 走看看