zoukankan      html  css  js  c++  java
  • ssoj 2279 磁力阵

    说不想改最后还是向T1屈服了。。然后就de了一下午Bug。。。

    虽然昨天随口扯的有点道理,正解就是迭代加深A星搜索,但实际写起来就十分难受了。

    说自己的做法,略鬼畜。

    每个正方形的边界上的边、每条边在哪些正方形上,都可以用一个Long Long的二进制串表示。给每个矩形编号,预处理每个矩形对应边的串,每条边对应矩形的串,每个矩形对应矩形(它的所有边对应矩形的并集,之后估价会用)。

    然后就直接迭代搜索,存一个串表示现在哪些正方形处理完了,每次找出第一个没处理的正方形,枚举每条边试图处理它。用一个估价函数判断现在有没有必要继续搜:找当前状态所有未处理的正方形,把它的所有边处理掉,遇到一个就res++,若res+cnt>limit 就return 0;

    几个坑点,可能只有自己会被坑。。。

    1.不用二进制优化会TLE,可能是我写得比较残,T2个点。。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    typedef long long LL;
    using namespace std;
    int T,n,totn,k,x,xx,tot,now,nowok,e[100][100],sq[100][100],ok[100],tpok[100],limit;
    void clear() {
        memset(e,0,sizeof(e));
        memset(sq,0,sizeof(sq));
        memset(ok,0,sizeof(ok));
        tot=0; nowok=0;
    }
    void link(int ed,int id) {
        e[ed][++e[ed][0]]=id;
        sq[id][++sq[id][0]]=ed;
    }
    void pre() {
        totn=0;
        for(int i=1;i<=n;i++) totn+=i*i;
        for(int k=0;k<=n;k++)
        for(int i=1;i<=n;i++) 
            for(int j=1;j<=n;j++)
                if(i+k<=n&&j+k<=n)
                 {
                    tot++;
                    for(int l=0;l<=k;l++) {
                        now=(i-1)*(2*n+1)+j+l;
                        link(now,tot);
                        now=(i+k)*(2*n+1)+j+l;
                        link(now,tot);
                    }
                    now=n+(i-1)*(2*n+1)+j; 
                    link(now,tot); 
                    link(now+k+1,tot);
                    for(int l=1;l<=k;l++) {
                        now+=(2*n+1);
                        link(now,tot);
                        link(now+k+1,tot);
                    }
                }
    }
    int check(int x,int c,int li) {
        memset(tpok,0,sizeof(tpok));
        int res=0;
        for(int i=1;i<=totn;i++)
        if(!ok[i]&&!tpok[i]) {
             res++;
             for(int j=1;j<=sq[i][0];j++) {
                 int u=sq[i][j];
                 for(int l=1;l<=e[u][0];l++) 
                     tpok[e[u][l]]=1;
             }
        }
        return res;
    }
    int dfs(int cnt,int no,int lim) {
        if(cnt>lim) return 0;
        if(!no) return 1;
        int tp[100],flag=0;
        memset(tp,0,sizeof(tp));
        for(int i=1;i<=totn;i++) if(flag) break; else {
           if(!ok[i]){
               flag=1;
            for(int j=1;j<=sq[i][0];j++) {
                xx=0;   tp[0]=0;
                x=sq[i][j];
                for(int l=1;l<=e[x][0];l++) {
                   if(!ok[e[x][l]]) {tp[++tp[0]]=e[x][l]; xx++;}
                   ok[e[x][l]]=1;
                }   
                if(check(sq[i][j],cnt,lim)+cnt<=lim) {
                    if(dfs(cnt+1,no-xx,lim)) return 1;
                }
                for(int i=1;i<=tp[0];i++)
                    ok[tp[i]]=0;
            }
           }
        }
        return 0;
    }
    int main()
    {
        freopen("mag.in","r",stdin);
        freopen("mag.out","w",stdout);
        scanf("%d",&T);
        while(T--) {
            scanf("%d%d",&n,&k);
            clear();
            pre();
            for(int i=1;i<=k;i++) {
                scanf("%d",&x);
                for(int j=1;j<=e[x][0];j++) {
                    if(!ok[e[x][j]]) nowok++;
                    ok[e[x][j]]=1;
                }
            }
            for(limit=0;limit<=60;limit++) {
                if(dfs(0,totn-nowok,limit)) {
                    printf("%d
    ",limit);
                    break;
                }
            }
        }
        return 0;
    }
    View Code

    2.搜索的时候只需要搜当前状态第一个不满足的正方形,因为其他在之后的状态中是可以搜到的,不然会T8个点。。。

    3.正方形的编号,因为搜索是按编号搜的,要先编小正方形再编大的。。自行体会。。会T两个点,速度是0.2秒和10.2秒的差距。。。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    typedef long long LL;
    using namespace std;
    int T,n,totn,k,x,xx,now,tot,nowok,sqq[100][100];
    LL e[100],sq[100],val[100],st,limit,N;
    void clear() {
        memset(e,0,sizeof(e));
        memset(sq,0,sizeof(sq));
        memset(sqq,0,sizeof(sqq));
        memset(val,0,sizeof(val));
        tot=0; st=0;
    }
    void link(int ed,int id) {
        e[ed]|=1LL<<(id-1);
        sq[id]|=1LL<<(ed-1);
        sqq[id][++sqq[id][0]]=ed;
    }
    void pre() {
        totn=0;
        for(int i=1;i<=n;i++) totn+=i*i;
        N=(1LL<<totn)-1;
        for(int k=0;k<=n;k++)
            for(int i=1;i<=n;i++) 
                for(int j=1;j<=n;j++) 
                if(i+k<=n&&j+k<=n)
                 {
                    tot++;
                    for(int l=0;l<=k;l++) {
                        now=(i-1)*(2*n+1)+j+l;
                        link(now,tot);
                        now=(i+k)*(2*n+1)+j+l;
                        link(now,tot);
                    }
                    now=n+(i-1)*(2*n+1)+j; 
                    link(now,tot); 
                    link(now+k+1,tot);
                    for(int l=1;l<=k;l++) {
                        now+=(2*n+1);
                        link(now,tot);
                        link(now+k+1,tot);
                    }
                }
        for(int i=1;i<=totn;i++) {
            for(int j=1;j<=sqq[i][0];j++) {
                val[i]|=e[sqq[i][j]];
            }
        }
    }
    int check(LL now,int c,int li) {
        int res=0;
        for(int i=1;i<=totn-1;i++) {
            if(!(now&(1LL<<i-1))) {
                res++;
                if(res+c>li) return 0;
                now|=val[i];
            }
        }
        return res+c<=li;
    }
    int dfs(int cnt,LL now,int lim) {
        if(cnt>lim) return 0;
        if(now==N) return 1;
        LL tmp;
        if(!check(now,cnt,lim)) return 0;
        int flag=0;
        for(int i=1;i<=totn;i++) if(flag) break; else{
           if(!(now&(1LL<<i-1))){
                   flag=1; 
                
                   for(int j=1;j<=sqq[i][0];j++) {
                       tmp=now|e[sqq[i][j]];
                    //if(check(tmp,cnt,lim)) {
                    if(dfs(cnt+1,tmp,lim)) return 1;
                    //}  
                   }
           }
        }
        return 0;
    }
    int main()
    {
        freopen("mag.in","r",stdin);
        freopen("mag.out","w",stdout);
        scanf("%d",&T);
        while(T--) {
            scanf("%d%d",&n,&k);
            clear();
            pre();
            for(int i=1;i<=k;i++) {
                scanf("%d",&x);
                st|=e[x];
            }
            for(limit=0;limit<=60;limit++) {
                if(dfs(0,st,limit)) {
                    printf("%d
    ",limit);
                    break;
                }
            }
        }
        return 0;
    }
    AC
  • 相关阅读:
    Java多线程详解
    自动化构建工具Maven
    解决 安装cocoapods失败,提示 requires Ruby version >=2.2.2
    安装Cocoapods时候ERROR: While executing gem ... (Errno::EPERM)
    iOS可执行文件瘦身方法
    ios webview自适应实际内容高度4种方法
    iOS8 tableview separatorInset cell分割线左对齐,ios7的方法失效了
    Reveal1.5破解,iOS_UI调试利器Reveal最新版本破解方法
    Xcode安装插件,错误选择了Skip Bundles,重新出现Load Bundles方法
    10分钟搞定支付宝支付 的 各种填坑
  • 原文地址:https://www.cnblogs.com/Achenchen/p/7531782.html
Copyright © 2011-2022 走看看