暴搜 - 狀態壓縮 - Scaring the Birds - HDU - 4462

暴搜 - 狀態壓縮 - Scaring the Birds - HDU - 4462

題意:

nm(xi,yi),ri,i[1,m]多組測試用例。\\每組包括方陣的階n,允許擺放稻草人的m個位置(x_i,y_i),以及每個位置能夠覆蓋的範圍r_i,i∈[1,m]。

n×n要求至少擺放多少個稻草人,才能覆蓋整個n×n的稻田。

()這裏的覆蓋範圍是曼哈頓距離(兩點間橫縱座標差的和)。

Sample Input:
4
2
2 2 3 3
1 3
4
2
2 2 3 3
1 4
0
Sample Output:
-1
1

數據範圍:

2<=n<=500<=m<=101<=xi,yi<=nri<=2nTime limit1000msMemory limit32768kB2<=n<=50,0<=m<=10,1<=x_i,y_i<=n,r_i<=2n。\\Time \ limit:1000 ms,Memory \ limit:32768 kB


分析:

mm共有m個位置可選擇,可用一個長度爲m的二進制數來表示當前方案。

2m10210×50×50×102.5×107共有2^m種方案,每種方案在最壞、最暴力的情況會全圖搜索10次,\\計算次數上限大約爲2^{10}×50×50×10≈2.5×10^7。

1s50ms儘管是最暴力的方式枚舉,仍然可以在1s內跑完。事實上測試不到50ms就跑完了。

具體落實:

[0,2m1]vis①、從[0,2^m-1],每次枚舉一種狀態,對每種狀態用一個vis數組標記哪些點能夠被覆蓋到,\\\qquad這裏需要注意,允許擺放稻草人的位置可以不必覆蓋。

1j(xj,yj)2rj滿xxj+yyj<=rj②、枚舉當前狀態上的1,從這個狀態所表示的j點的位置開始暴力標記一個以(x_j,y_j)爲中心,2r_j爲邊長的方陣,\\\qquad只要這個方陣內的點在半徑覆蓋範圍內,就將其標記。即方陣內滿足|x-x_j|+|y-y_j|<=r_j的所有點。

③、統計當前狀態標記了方陣上多少個點,若所有點均被覆蓋了,就更新一下答案。

代碼:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<vector>

#define P pair<int,int>
#define x first
#define y second
#define ll long long
#define inf 0x3f3f3f3f

using namespace std;

const int N=55,M=1<<10;

int n,m,r[N];
P v[15];
bool vis[N][N];

void dfs(int x,int y,int r)
{
    for(int i=max(1,x-r);i<=min(x+r,n);i++)
        for(int j=max(1,y-r);j<=min(y+r,n);j++)
            if(abs(i-x)+abs(j-y)<=r)
                 vis[i][j]=true;
}

int main()
{
    while(~scanf("%d",&n),n)
    {
        scanf("%d",&m);
        for(int i=0;i<m;i++) scanf("%d%d",&v[i].x,&v[i].y);
        for(int i=0;i<m;i++) scanf("%d",&r[i]);

        int ans=inf;
        for(int i=0;i<M;i++)
        {
            memset(vis,false,sizeof vis);
            for(int k=0;k<m;k++) vis[v[k].x][v[k].y]=true;
            int cnt=0;
            for(int j=0;j<m;j++)
                if((i>>j)&1)
                {
                    dfs(v[j].x,v[j].y,r[j]);
                    cnt++;
                }

            int tmp=0;
            for(int k=1;k<=n;k++)
                for(int j=1;j<=n;j++)
                    if(vis[k][j])
                        tmp++;
            if(tmp==n*n) ans=min(ans,cnt);
        }

        if(ans!=inf) printf("%d\n",ans);
        else puts("-1");
    }

    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章