P2831 愤怒的小鸟
刚开始拿到这题,想着打个暴力。
(0,0)和猪所在的点,至少两个点可以确定曲线 y=ax2+bx 中的a和b,然后把这条线和线上的点(也就是上面的猪)的vis[i]=1,避免重复。
a,b计算式:(我知道大家很强,但我还是要提醒一下自己)
打完交上去只有40分
40分代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ll long long using namespace std; int n,m,t; double x[20],y[20],old[500][5]; double pa(double x1,double y1,double x2,double y2){ return ((y1*x2-x1*y2)/((x1-x2)*x2*x1)); } double pb(double a,double x1,double y1){ return ((y1-a*x1*x1)/x1); } int main(){ double a,b; scanf("%d",&t); while(t--){ int maxn=0; int vis[20]={0}; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%lf%lf",&x[i],&y[i]); } for(int i=1;i<n;i++){ for(int j=i+1;j<=n;j++){ if(x[i]==x[j]) continue; a=pa(x[i],y[i],x[j],y[j]); if(a>=0) continue; b=pb(a,x[i],y[i]); for(int k=1;k<=maxn;k++){ if(a==old[k][1]&&b==old[k][2]){ vis[i]=vis[j]=1; break; } } if(!vis[i]&&!vis[j]){ maxn++; old[maxn][1]=a; old[maxn][2]=b; vis[i]=vis[j]=1; } } } for(int i=1;i<=n;i++){ if(!vis[i]) maxn++; } printf("%d ",maxn); } return 0; }
之后老老实实拿状压做了......
对于每只猪考虑两种情况: 自己被单独打下来或者被其他抛物线经过打下来
但是两点无法确定一条抛物线,也就是说这个抛物线可以自己设
所以说一只鸟打下来一个猪一定可行
但若能多打一只猪更好
暴力找两只没被打下来(vis==0)的猪
作抛物线,看看还能打下来几只
不断更新dp。
注意:
1.预处理出所有抛物线能打几只猪, 可以省一维枚举每只猪,不然可能T掉
2.此题卡精度, 判断两个浮点数是否相等可以确定一个精度然后去比,这题是1e-7?好像...
AC码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ll long long using namespace std; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } int t,n,m; int dp[1<<18],old[210],tot=0; void work(double &a,double &b,double x1,double y1,double x2,double y2) { a=(x2*y1-x1*y2)/(x1*x2*(x1-x2)); b=(x1*x1*y2-x2*x2*y1)/(x1*x2*(x1-x2)); } bool sa(double a,double b,double x,double y) { double abs=a*x*x+b*x-y; if(abs<0) abs= -abs; if(abs<0.000001) return true; else return false; } int ans() { dp[0] = 0; for(int i=0;i<=(1<<n)-1;i++) { for(int j=0;j<=tot-1;j++) { dp[i|old[j]]=min(dp[i|old[j]],dp[i]+1); } } return dp[(1<<n)-1]; } int main() { read(t); while(t--) { memset(dp,0x3f,sizeof(dp));//我就是要写memset,作死 tot=0; double x[20],y[20]; read(n);read(m); for(int i=0;i<=n-1;i++) { scanf("%lf%lf",&x[i],&y[i]); } for(int i=0;i<=n-1;i++) { old[tot++]=(1<<i); for(int j=i+1,vis=0;j<n;j++) { if((vis>>j)&i!=0) continue; else { double a,b; work(a,b,x[i],y[i],x[j],y[j]); if(a>=0) continue; old[tot]=(1<<i); for(int k=j;k<=n-1;k++) { if(sa(a,b,x[k],y[k])) { vis|=(1<<k); old[tot]|=(1<<k); } } tot++; } } } printf("%d ",ans()); } return 0; }
2019-07-30 21:11:41