【状压DP】NOIP2016Day2T3[愤怒的小鸟]题解

来源:互联网 发布:淘宝网外贸店 编辑:程序博客网 时间:2024/05/16 23:52

解题报告

好像是比较简单的状压DP,我有一个数组没有清 0 ,如果是全国联赛就炸了……

定义 f[s] 表示状态为 s 的最优解,那么每次枚举 ij ,用一条抛物线穿过去,并计算出新状态 t ,用 f[s]+1 修正 f[t]

每次都枚举太慢,我们可以直接预处理 g[i][j] 表示穿过 ij 打掉的猪的集合,最后再注意一下只打一头猪的情况。

示例程序

#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#define fr first#define sc second#define mp make_pairusing namespace std;typedef double DB;const int maxn=18,maxm=(1<<maxn);int te,n,m,g[maxn][maxn],f[maxm];pair<DB,DB> p[maxn];inline int fcmp(DB a,DB b) {if (fabs(a-b)<1e-10) return 0;if (a<b) return -1;return 1;}int main(){    freopen("angrybirds.in","r",stdin);    freopen("angrybirds.out","w",stdout);    for (scanf("%d",&te);te;te--)    {        scanf("%d%d",&n,&m);m=(1<<n)-1;memset(g,0,sizeof(g));        for (int i=0;i<n;i++) scanf("%lf%lf",&p[i].fr,&p[i].sc);sort(p,p+n);        for (int i=0;i<n-1;i++)        for (int j=i+1;j<n;j++) if (fcmp(p[i].fr,p[j].fr))        {            DB A,B;A=(p[j].sc*p[i].fr/p[j].fr-p[i].sc)/(p[i].fr*p[j].fr-p[i].fr*p[i].fr);            if (fcmp(A,0)>=0) continue;B=(p[i].sc-A*p[i].fr*p[i].fr)/p[i].fr;            for (int k=0;k<n;k++) if (!fcmp(A*p[k].fr*p[k].fr+B*p[k].fr,p[k].sc)) g[i][j]|=1<<k;        }        memset(f,63,sizeof(f));f[0]=0;        for (int s=0;s<m;s++)        for (int i=0;i<n;i++) if (!(s&(1<<i)))        {            for (int j=i+1;j<n;j++)                f[s|g[i][j]]=min(f[s|g[i][j]],f[s]+1);            f[s|(1<<i)]=min(f[s|(1<<i)],f[s]+1);        }        printf("%d\n",f[m]);    }    return 0;}