zoukankan      html  css  js  c++  java
  • [bzoj1210][HNOI2004]邮递员【插头dp】

    【题目链接】
      https://www.lydsy.com/JudgeOnline/problem.php?id=1210
    【题解】
      一道插头dp的入门题。
      粗略来说就是从上往下,从左往右一格一格dp,用状态压缩的方法记录与未搜索格子的连通性(最小表示法或括号法)。
      具体可见陈丹琦的:《基于连通性状态压缩的动态规划问题》
      时间复杂度O(NM22(M+1)) 实际远远不到。
      

    /* --------------
        user Vanisher
        problem bzoj-1210
    ----------------*/
    # include <bits/stdc++.h>
    # define    ll      long long
    # define    inf     0x3f3f3f3f
    using namespace std;
    int read(){
        int tmp=0, fh=1; char ch=getchar();
        while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
        while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
        return tmp*fh;
    }
    const int L=21, N=110,T=(1<<22);
    struct INT{
        int num[N],len;
        void reget(){
            int i;
            for (i=1; i<=len||num[i]!=0; i++)
                num[i+1]+=num[i]/10, num[i]=num[i]%10;
            len=i-1;
        }
        void tonum(char *s){
            len=strlen(s+1);
            for (int i=1; i<=len; i++) num[len-i+1]=s[i]-'0';
        }
        void operator =(int tmp){
            memset(this->num,0,sizeof(this->num));
            this->len=0;
            while (tmp!=0) 
                this->num[++(this->len)]=tmp%10, tmp/=10;
        }
        INT operator +(INT b){
            INT c=*this; int i; c.len=max(c.len,b.len);
            for (i=1; i<=c.len; i++) c.num[i]=c.num[i]+b.num[i];
            c.reget(); return c;
        }
        INT operator *(INT b){
            INT c; c.len=b.len+len-1; int i,j;
            memset(c.num,0,sizeof(c.num));
            for (i=1; i<=len; i++)  
                for (j=1; j<=b.len; j++)
                    c.num[i+j-1]=c.num[i+j-1]+num[i]*b.num[j];
            c.reget(); return c;
        }
        INT operator *(int tmp){ INT b; b=tmp; return ((*this)*b);}
        INT operator +(int tmp){ INT b; b=tmp; return ((*this)+b);}
        void read(){ char s[N]; scanf("%s",s+1); tonum(s); }
        void print(){
            if (len==0){ printf("0
    "); return; }
            for (int i=len; i>=1; i--) printf("%d",num[i]);
            printf("
    ");
        }
    }one,ans;
    vector <INT> f[2];
    vector <int> g[2];
    int n,m,now[N],nex[N],f1,f2,lim,h[T],p[T],id;
    int getnum(){
        int num=0;
        for (int i=0; i<m+1; i++)
            num=num+(nex[i]<<(i*2));
        return num;
    } 
    void join(INT num){
        int tmp=getnum();
        if (h[tmp]==-1){
            h[tmp]=f[f2].size();
            p[f[f2].size()]=tmp;
            f[f2].push_back(num);
            g[f2].push_back(tmp);
        }
        else f[f2][h[tmp]]=f[f2][h[tmp]]+num;
    }
    int main(){
        n=read(), m=read();
        if (n==1||m==1){
            printf("1
    ");
            return 0;
        }
        if (n<m) swap(n,m);
        one=1;
        f1=0, f2=1, lim=(1<<((m+1)*2));
        f[f1].push_back(one); 
        g[f1].push_back(1+(2<<(1*2)));
        memset(h,-1,sizeof(h));
        for (int i=0; i<n; i++){
            for (int j=0; j<m; j++){
                if (i==0&&j==0) continue;
                for (unsigned k=0; k<g[f1].size(); k++) h[p[k]]=-1;
                for (unsigned k=0; k<g[f1].size(); k++){
                    if (g[f1][k]>=lim) continue;
                    INT num=f[f1][k];
                    for (int t=0; t<m+1; t++)
                        now[t]=nex[t]=(g[f1][k]>>(t*2))&3;
                    if (now[j]!=0&&now[j+1]!=0){
                        if (now[j]==1&&now[j+1]==2&&i==n-1&&j==m-1) 
                            if (g[f1][k]-(now[j]<<(j*2))-(now[j+1]<<(j*2+2))==0)
                                ans=ans+num;
                        if (now[j]==2&&now[j+1]==1) 
                            nex[j]=0, nex[j+1]=0, join(num);
                        if (now[j]==2&&now[j+1]==2){
                            nex[j]=0, nex[j+1]=0;
                            int t=j-1, cnt=0;
                            while (!(cnt==0&&now[t]==1)){
                                if (now[t]==1) cnt--;
                                if (now[t]==2) cnt++;
                                t--;
                            }
                            nex[t]=2; join(num);
                        }
                        if (now[j]==1&&now[j+1]==1){
                            nex[j]=0, nex[j+1]=0;
                            int t=j+2, cnt=0;
                            while (!(cnt==0&&now[t]==2)){
                                if (now[t]==2) cnt--;
                                if (now[t]==1) cnt++;
                                t++;
                            }
                            nex[t]=1; join(num);
                        }
                    }
                    if (now[j]==0&&now[j+1]!=0){
                        nex[j]=0, nex[j+1]=now[j+1]; join(num);
                        nex[j]=now[j+1], nex[j+1]=0; join(num);
                    }
                    if (now[j]!=0&&now[j+1]==0){
                        nex[j]=0, nex[j+1]=now[j]; join(num);
                        nex[j]=now[j], nex[j+1]=0; join(num);
                    }
                    if (now[j]==0&&now[j+1]==0){
                        nex[j]=1, nex[j+1]=2; join(num);
                    }   
                }
                swap(f1,f2);
                g[f2].clear(); f[f2].clear();
            }
            for (unsigned k=0; k<g[f1].size(); k++) g[f1][k]=g[f1][k]<<2;
        }
        ans=ans*2;
        ans.print();
        return 0;
    }
    
  • 相关阅读:
    架构漫谈阅读笔记(1)
    第一周学习进度
    2月13号寒假总结
    2月12日寒假总结
    2月11日寒假总结
    2月10日寒假总结
    寒假学习进度笔记一
    mapreduce课上实验
    个人课程总结
    用户体验评价
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9135957.html
Copyright © 2011-2022 走看看