hdu 4462 Scaring the Birds 状态压缩

来源:互联网 发布:泳衣品牌知乎 编辑:程序博客网 时间:2024/05/22 11:47

题意:一个n*n的区域,有m个位置是可以放稻草人的,其余都是玉米。对于每个位置(x,y)所放稻草人都有个作用范围ri,即abs(x-i)+abs(y-j)<=r,(i,j)为作用范围内。问至少要在几个位置上放稻草人,才能覆盖所有的玉米,若不可能则输出-1。

题解:可放稻草人位置个数m<=10,所以可以状态压缩(就是枚举0~(1<<m)-1。对于枚举的每个数,表示成m位二进制,从右开始,第几位是1表示放稻草人,否则不放。这样就可以用2^10时间,枚举所有状况,称为状态压缩),枚举所有情况,对于每种情况,遍历所有有玉米的点判断是否可以被覆盖即可。为什么是枚举所有有玉米点而不是广搜,这就是复杂度的问题了,详细在注意事项内。

注意:

1.对于每种情况,如果用光搜,由于没有结束判断,所以要遍历所有的作用范围内的点。以最坏情况记,每种情况都要遍历n^2*k(k为情况中要放稻草人的位置数)次。这种复杂度有点高,至于会不会爆,就没试过了。。而枚举所有玉米点,就只用n^2时间了。

2.还有注意的是,放稻草人的位置不用覆盖。。一开始没发现,wa了3次。。



耗时:0MS

#include <cstdio>#include <cmath>#include <cstring>#include <algorithm>#include <iostream>using namespace std;typedef __int64 LL;const int INF=1e9;const int maxn=3000;struct node{    int x,y,r; }e[11],f[11];int ans,map[55][55];int get_sum(int a){    int s=0;    while(a)    {        if(a&1)s++;        a=a>>1;    }    return s;}void find(int x,int n){    int i=0,j,k,t=0,tt;    tt=get_sum(x);    if(tt>=ans)return;    while(x)    {        if(x&1)        {            f[t++]=e[i];        }        x=x>>1;        i++;    }    //cout<<t<<endl;    for(i=1;i<=n;i++)    {        for(j=1;j<=n;j++)        {            if(map[i][j])continue;            for(k=0;k<t;k++)            {                if(abs(f[k].x-i)+abs(f[k].y-j)<=f[k].r)break;            }            if(k>=t)return;        }    }    ans=tt;}int main(){    int n;    while(scanf("%d",&n)!=EOF)    {        if(n==0)break;        int i,j,k,m,t,p,q;        memset(map,0,sizeof(map));        ans=INF;        scanf("%d",&m);        for(i=0;i<m;i++)        {            scanf("%d%d",&e[i].x,&e[i].y);            map[e[i].x][e[i].y]=1;        }        for(i=0;i<m;i++)        scanf("%d",&e[i].r);        find((1<<m)-1,n);        //cout<<n<<endl;        if(ans==INF){printf("-1\n");continue;}        for(i=0;i<(1<<m);i++)            find(i,n);        printf("%d\n",ans);    }    return 0;}


原创粉丝点击