《算法竞赛进阶指南》0x28IDA* POJ1084 Square Destoryer

题目链接:https://www.acwing.com/problem/content/184/

给出正方形和某些边被删除,要求删除最少的边数使得其中没有任何正方形,策略就是将所有的正方形都存起来,可以从图中看见正方形的四条边都是等差数列,边长为5的大正方形拥有60条小边

接下来只要枚举最小的正方形,并且删除每条边,向下一个状态转移,如果删除所有的边都无法在指定的深度达到目标状态,就return false,return true的条件是没有完整的正方形,

在此我们需要用IDA*估计未来至少需要的步数f(),计算方式是看有多少个完整的独立的正方形,每个独立的正方形一定至少删除一条边,所以未来的代价一定是大于等于我们估计的代价的,满足估价函数

的性质,估价函数在计算中需要将完整边数的正方形的所有边都删除,需要使用一个新的bool数组保存边原来的情况,计算完成后再复制回去。

注意点就是dfs中的return条件

代码:

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 80
int n,m;
bool st[maxn];//标记编号是否拿走 
vector<int> square[maxn];//保存每个正方形的边长,等差数列 
bool state[maxn];

bool check(vector<int> &sq){
    for(int i=0;i<sq.size();i++)
        if(st[sq[i]])
            return false;
    return true;
}

int f(){//计算当前有多少个完整的正方形 
    
    memcpy(state,st,sizeof(st));
    
    int ret=0; 
    for(int i=0;i<m;i++){
        vector<int> &sq = square[i];
        if(check(sq)){
            ret++;
            for(int j=0;j<sq.size();j++){//将该正方形的所有边都删除 
                st[sq[j]]=true;
            }
        }
    } 
    memcpy(st,state,sizeof(state));
    
    return ret;
}
bool dfs(int depth,int max_depth){
    
    if(depth+f() > max_depth)return false;
    
    for(int i=0;i<m;i++){
        vector<int> &sq = square[i];
        if(check(sq)){//最小的完整的正方形 
            for(int j=0;j<sq.size();j++){
                int x=sq[j];
                st[x]=true;
                if(dfs(depth+1,max_depth))return true;
                st[x]=false;
            }
            return false;//最小的正方形删边之后无法成功搜索 
        } 
    }
    
    return true;//没有完整的正方形 
}
int main(){
    int T;
    cin>>T;
    while(T--){
        scanf("%d",&n);
        memset(st,0,sizeof(st));
        m=0;
        for(int len=1;len<=n;len++)//枚举边长 
            for(int a=1;a+len-1<=n;a++)//枚举左上角的起点 
                for(int b=1;b+len-1<=n;b++)
                {
                    square[m].clear();
                    int d=2*n+1;//保存公差 
                    for(int i=0;i<len;i++){//插入4*len条边 
                        square[m].push_back(1+(a-1)*d+b-1+i);//上边,等差数列 
                        square[m].push_back(1+(a+len-1)*d+b-1+i);//下边 
                        square[m].push_back(n+1+(a-1)*d+b-1+i*d);//左边 
                        square[m].push_back(n+1+(a-1)*d+b-1+i*d+len);//右边 
                    }
                    m++;
                }    
        int k=0;
        scanf("%d",&k);        
        while(k--){
            int x;
            scanf("%d",&x);
            st[x]=true; 
        }
        
        int depth=0;
        while(!dfs(0,depth))depth++;
        
        printf("%d\n",depth); 
    } 
}

 

 

 

https://www.acwing.com/problem/content/184/

posted @ 2020-06-22 12:35  WA自动机~  阅读(228)  评论(0编辑  收藏  举报