luogu2831 [NOIp2016]愤怒的小鸟 (状压dp)

由范围可以想到状压dp

两个点(再加上原点)是可以确定一个抛物线的,除非它们解出来a>=0,在本题中是不合法的

这样的话,我们可以预处理出由任意两个点确定的抛物线所经过的所有的点(要特别规定一下自己和自己确定的抛物线只经过自己)

然后设状态s表示目前已经有哪些点被击中了,然后我们钦定这次就要打那个最小的还没击中的点(因为吃枣都要打的嘛),再枚举出另一个还没经过的点,就能得到转移方程

$f[s|line[i][j]]=max{f[s]+1}$,其中$line[i][j]$表示i、j两点确定的抛物线经过的所有的点,i是s中还未击中的最小的点

复杂度是$O(n2^n)$

 1 #include<bits/stdc++.h>
 2 #define pa pair<int,int>
 3 #define lowb(x) ((x)&(-(x)))
 4 #define REP(i,n0,n) for(i=n0;i<=n;i++)
 5 #define PER(i,n0,n) for(i=n;i>=n0;i--)
 6 #define MAX(a,b) ((a>b)?a:b)
 7 #define MIN(a,b) ((a<b)?a:b)
 8 #define CLR(a,x) memset(a,x,sizeof(a))
 9 #define rei register int
10 using namespace std;
11 typedef long long ll;
12 const int maxn=20,maxs=1000000;
13 
14 inline ll rd(){
15     ll x=0;char c=getchar();int neg=1;
16     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
17     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
18     return x*neg;
19 }
20 
21 int N;
22 double pos[maxn][2];
23 int line[maxn][maxn];
24 int f[maxs],bin[maxn];
25 
26 inline bool eq(double a,double b){return fabs(a-b)<=1e-8;}
27 inline void getab(double &a,double &b,double x1,double y1,double x2,double y2){
28     a=(x2*y1-x1*y2)/(x1*x2*(x1-x2));
29     b=(x1*x1*y2-x2*x2*y1)/(x1*x2*(x1-x2));
30 }
31 
32 int main(){
33     // freopen("testdata.in","r",stdin);
34     int i,j,k;
35     for(i=1,j=1;i<=19;i++,j<<=1) bin[i]=j;
36     for(int T=rd();T;T--){
37         N=rd();rd();
38         for(i=1;i<=N;i++) scanf("%lf%lf",&pos[i][0],&pos[i][1]);
39         for(i=1;i<=N;i++){
40             for(j=i+1;j<=N;j++){
41                 double a,b;getab(a,b,pos[i][0],pos[i][1],pos[j][0],pos[j][1]);
42                 
43                 int s=0;
44                 if(a<0){
45                     for(k=1;k<=N;k++ ){
46                         if(eq(a*pos[k][0]*pos[k][0]+b*pos[k][0],pos[k][1])){
47                             s|=bin[k];
48                         }
49                     }
50                 }
51                 line[i][j]=s;
52                 // cout<<a<<" "<<b<<" "<<i<<" "<<j<<" "<<bitset<20>(s)<<endl;
53             }line[i][i]=bin[i];
54         }
55         memset(f,127,sizeof(f));
56         f[0]=0;
57         for(i=0;i<bin[N+1]-1;i++){
58             for(j=1;bin[j]&i;j++);
59             for(k=j;k<=N;k++){
60                 if(bin[k]&i) continue;
61                 f[i|line[j][k]]=min(f[i|line[j][k]],f[i]+1);
62             } 
63         }printf("%d
",f[bin[N+1]-1]);
64     }
65    
66     return 0;
67 }
原文地址:https://www.cnblogs.com/Ressed/p/9696043.html