1. 程式人生 > >noip2016 憤怒的小鳥 狀壓搜尋

noip2016 憤怒的小鳥 狀壓搜尋

這道題稍微卡了一下精度,浮點數直接判相等是會掛掉的。然後就是搜尋,選定當前未選的最小編號,列舉其他的點確定一條拋物線(如果可以),然後把在這條線上的點都選上。確定拋物線推一下就可以。

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstdlib>
#include<map>
#define LL long long
using namespace std;
int n,m;
double zx[20],zy[20];
bool use[20];
double A[50
],B[50]; bool check(int p1,int p2,int i) { double x1=zx[p1]*zx[p1]; double y1=zx[p1]; double c1=zy[p1]; double x2=zx[p2]*zx[p2]; double y2=zx[p2]; double c2=zy[p2]; B[i]=(x1*c2-x2*c1)/(x1*y2-x2*y1); A[i]=(c1-B[i]*y1)/x1; if(A[i]<0) return true; return false; } double
eps=0.000001; bool Check(int p1,int i) { double x1=zx[p1]*zx[p1]; double y1=zx[p1]; if(A[i]*x1+B[i]*y1<=zy[p1]+eps&&A[i]*x1+B[i]*y1>=zy[p1]-eps) return true; return false; } int ans=20; int S[50],top; struct E{int Z,step;}; queue<E> Q; int T; map<LL,bool> mp[35
]; void bfs() { while(!Q.empty()) { E W=Q.front();Q.pop(); int Z=W.Z,step=W.step; int p=0;int mn=0; while(p<n) { use[++p]=Z&1; if(!use[p]&&!mn) mn=p; Z>>=1; } if(!mn) { ans=W.step; return ; } use[mn]=1; for(int i=mn+1;i<=n;i++) if(!use[i]&&check(mn,i,step)) { use[i]=1;int cnt=0; for(int j=i+1;j<=n;j++) { if(!use[j]&&Check(j,step)) { S[++top]=j; use[j]=1;cnt++; } } LL z=0; for(int j=n;j>=1;j--) { z<<=1; if(use[j])z|=1; } E x=(E){z,step+1}; if(!mp[T][z]){Q.push(x);mp[T][z]=1;} while(cnt--) { use[S[top]]=0; top--; } use[i]=0; } LL z=0; for(int j=n;j>=1;j--) { z<<=1; if(use[j])z|=1; } E x=(E){z,step+1};Q.push(x); } } int main() { scanf("%d",&T); while(T--) { ans=1e9; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lf%lf",&zx[i],&zy[i]); while(!Q.empty()) Q.pop(); E w;w.step=0;w.Z=0; Q.push(w);bfs(); printf("%d\n",ans); } return 0; }