zoukankan      html  css  js  c++  java
  • 《算法竞赛进阶指南》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
    ",depth); 
        } 
    }

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

  • 相关阅读:
    向MyEclipse添加Oracle数据库
    如何让搜索引擎抓取AJAX内容?
    XCode常用快捷键
    VMware Workstation 9上安装Mac OS X 10.8
    IOS学习第一篇——利用Xcode中的Interface Builder创建Hello World示例
    FM 101.7
    SqlServer游标操作
    添加COOKIE
    c#活动目录操作
    WCF服务调用方式
  • 原文地址:https://www.cnblogs.com/randy-lo/p/13176221.html
Copyright © 2011-2022 走看看