zoukankan      html  css  js  c++  java
  • NOIP2004 虫食算

    题面https://www.luogu.org/problemnew/show/P1092

    肯定要从右到左,从上到下比较好处理。

    必然记录一个数用过与否,某个字母是什么。

    剪枝:

    1.到了第三行,上面两个已经确定,可以判断。

    2.往后预估。但是进位怎么考虑??

    没有关系!进位最多一位!!

    如果对于已经填好2个的3元组,可以推出另外一个的2种可能情况,如果都被占据,return false

    对于3个都填好了。也可以这样判断。

    (官方正解是高斯消元,但是我认为复杂度不对,因为数据水,好像没有21以上的n)

    代码:

    (数据的原因,倒序枚举更快)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=28;
    char mp[4][N];
    int is[N];
    bool has[N];
    int ans[N];
    int n;
    int num[4][N];
    bool fl;
    int lp(int x,int y){
        return mp[x][y]-'A';
    }
    bool che(int st){
        //return true;
        int jin=0;//return true;
        for(int j=st;j>=1;j--){
            int a=is[lp(1,j)],b=is[lp(2,j)],c=is[lp(3,j)];
            if(a!=-1&&b!=-1&&c!=-1){
                if(c!=(a+b)%n&&c!=(a+b+1)%n) return false;
            }
            else if(a!=-1&&b!=-1&&c==-1){
                if(has[(a+b)%n]&&has[(a+b+1)%n]) return false;
            }
            else if(a!=-1&&b==-1&&c!=-1){
                if(has[((c-a-1)+n)%n]&&has[((c-a)+n)%n]) return false;
            }
            else if(a==-1&&b!=-1&&c!=-1){
                if(has[((c-b-1)+n)%n]&&has[((c-b)+n)%n]) return false;
            }
        }
        return true;
    }
    void dfs(int x,int y,int jin){
        //cout<<x<<" and "<<y<<endl;
        if(fl) return;
        if(x==1&&y==0){
            if(jin) return;
            fl=true;
            memcpy(ans,is,sizeof is);return;
        }
        if(!che(y)) {
        return;
        }
        if(x==3){
            int a=is[mp[1][y]-'A'];
            int b=is[mp[2][y]-'A'];
            int tmp=a+b+jin;
            int to=tmp%n;
            if(is[mp[x][y]-'A']==-1){
                if(has[to]) return;
                has[to]=1;
                is[mp[x][y]-'A']=to;
                num[x][y]=to;
                dfs(1,y-1,tmp/n);
                has[to]=0;
                is[mp[x][y]-'A']=-1;
                num[x][y]=-1;
            }
            else{
                if(is[lp(x,y)]!=to) return;
                dfs(1,y-1,tmp/n);
            }
        }
        else{
            if(is[mp[x][y]-'A']==-1)
                for(int i=n-1;i>=0;i--){
                    if(!has[i]){
                        has[i]=1;
                        is[mp[x][y]-'A']=i;
                        num[x][y]=i;
                        dfs(x+1,y,jin);
                        has[i]=0;
                        is[mp[x][y]-'A']=-1;
                        num[x][y]=-1;
                    }
                }
            else {
                num[x][y]=is[lp(x,y)];
                dfs(x+1,y,jin);
                num[x][y]=-1;
            }
        }
    }
    int main(){
        scanf("%d",&n);
        fl=false;
        for(int i=1;i<=3;i++)scanf("%s",mp[i]+1);
        memset(is,-1,sizeof is);
        memset(num,-1,sizeof num);
        dfs(1,n,0);
        //cout<<fl<<endl;
        for(int i=0;i<n;i++){
            printf("%d ",ans[i]);
        }return 0;
    }

    总结:
    往后预估不一定要很准确。

    毕竟剪枝是玄学的。

    可以稍微放宽一些,反而更加有效。

  • 相关阅读:
    flash as3笔记1
    C# api 得到机器名
    Windows命令行 命令大全
    Adobe SVG View 动态修改src的问题
    onekeyghost 备份系统
    WCF寄存于Windows服务,通过Form进行调用
    RDLC报表自定义数据集
    电气工程图形符号
    解决Extjs TextField回车事件后刷新页面问题
    C# Windows服务自动安装与注册
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9779571.html
Copyright © 2011-2022 走看看