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
  • 相关阅读:
    Android Gradle Plugin指南(五)——Build Variants(构建变种版本号)
    文件内容操作篇clearerr fclose fdopen feof fflush fgetc fgets fileno fopen fputc fputs fread freopen fseek ftell fwrite getc getchar gets
    文件操作篇 close creat dup dup2 fcntl flock fsync lseek mkstemp open read sync write
    嵌入式linux应用程序调试方法
    version control system:git/hg/subversion/cvs/clearcase/vss。software configruation management。代码集成CI:Cruisecontrol/hudson/buildbot
    最值得你所关注的10个C语言开源项目
    如何记录linux终端下的操作日志
    CentOS 5.5 虚拟机安装 VirtualBox 客户端增强功能
    sizeof, strlen区别
    C/C++嵌入式开发面试题
  • 原文地址:https://www.cnblogs.com/Achenchen/p/7531782.html
Copyright © 2011-2022 走看看