愤怒的小鸟noip2017dayt3

游戏题。我自己在写大式子转移,自己晕头转向。hzw提醒我先预处理所有在同一线上的猪。然后将所有可能出现的打架状态进行枚举转移。先忘了处理除数是0,挂了一个点。

#include<iostream>
#include<algorithm> 
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;
const int maxn=(1<<20);
const double ex=1e-9;
int n,m,num,cnt;
int f[maxn],bir[maxn];//bir[],一只鸟可以打哪些猪 
struct node{
    double x,y;	
}p[20];
node find(int i,int j){
    node ans;
    double X1=p[i].x,Y1=p[i].y,
            X2=p[j].x,Y2=p[j].y;
    if(fabs(X1-X2)<ex){ans.x=1;return ans;}
    ans.x=(Y2-Y1*X2/X1)/(X2*X2-X1*X2); //除数要判0!!! 
    ans.y=Y1/X1-ans.x*X1;
     return ans; 
}
bool inlin(node l,node p){//点P是否在线l 上
    double y=l.x*p.x*p.x+l.y*p.x;
    if(fabs(y-p.y)<ex)return true;
    return false; 
}
void pre(){//处理1只鸟可以同时打哪些猪 
    for(int i=0;i<n;i++)
        for(int j=i+1;j<n;j++){
            node tmp;
            tmp=find(i,j);
            if(fabs(tmp.x)<ex)continue;
            if(tmp.x>=0)continue ;//这两只猪没法一起打
            bir[++cnt]=(1<<i)|(1<<j);
            for(int k=j+1;k<n;k++)
                if(inlin(tmp,p[k])){
                    bir[cnt]|=(1<<k); 
                }
        }
}

int dp(){
    memset(f,63,sizeof(f));
    f[0]=0;
    for(int i=0;i<num;i++)//1代表打了的猪,0代码没打 
    	for(int j=0;j<=cnt;j++)
    		f[i|bir[j]]=min(f[i|bir[j]],f[i]+1);
    return f[num-1];
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
    	scanf("%d%d",&n,&m);
    	for(int i=0;i<n;i++){ 
    	    scanf("%lf%lf",&p[i].x,&p[i].y);
            bir[i]=(1<<i); 
        }
        cnt=n-1; 
    	num=(1<<n);
    	pre();
    	int tmp=dp();	
    	printf("%d\n",tmp);
    }
} 



猜你喜欢

转载自blog.csdn.net/lengxuenong/article/details/79151561