• 【BZOJ】2310: ParkII 插头DP


    【题意】给定m*n的整数矩阵,求经过所有点至多一次路径的最大数值和。n<=8,m<=100。

    【算法】插头DP

    【题解】最小表示法确实十分通用,处理简单路径问题只需要状态多加一位表示独立插头的数量0~2(即路径端点),转移的时候多考虑凭空产生独立插头和结尾为独立插头的情况即可。

    可以跳格的情况直接转移就行。求最值路径和求路径数的区别就是把加改成乘。这样每行至多5种联通编号,用8进制即可。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int maxn=10,MOD=10007,S=3000010;
    int n,m,map[110][maxn],c[maxn],num;
    struct h{
        int first[MOD],nxt[S],state[S],tot;//
        ll ans[S];
        void init(){
            memset(first,0,sizeof(first));
            tot=0;
        }
        void insert(int x,ll num){
            for(int i=first[x%MOD];i;i=nxt[i]){
                if(state[i]==x){
                    ans[i]=max(ans[i],num);
                    return;
                }
            }
            state[++tot]=x;ans[tot]=num;
            nxt[tot]=first[x%MOD];first[x%MOD]=tot;
        }
    }f[2];
    void decode(int x){num=x&7;x>>=3;for(int i=m;i>=0;i--)c[i]=x&7,x>>=3;}
    int vis[10];//
    int encode(){
        for(int i=1;i<=6;i++)vis[i]=0;
        int cnt=0,x=0;
        for(int i=0;i<=m;i++){
            if(!c[i]){x<<=3;continue;}
            if(!vis[c[i]])vis[c[i]]=++cnt;
            x=(x<<3)|vis[c[i]];
        }
        return x=(x<<3)|num;
    }
    bool o(int x,int y){return x<=n&&y<=m;}
    void solve(int cur,int x,int y){
        for(int k=1;k<=f[cur^1].tot;k++){
            decode(f[cur^1].state[k]);
            int left=c[y-1],up=c[y];ll ans=f[cur^1].ans[k]+map[x][y];
            if(left&&up){
                if(left!=up){
                    c[y-1]=c[y]=0;
                    for(int i=0;i<=m;i++)if(c[i]==left)c[i]=up;
                    f[cur].insert(encode(),ans);
                }
            }
            else if(left||up){
                int now=left^up;
                if(o(x+1,y)){
                    c[y-1]=now;c[y]=0;
                    f[cur].insert(encode(),ans);
                }
                if(o(x,y+1)){
                    c[y-1]=0;c[y]=now;
                    f[cur].insert(encode(),ans);
                }
                if(num<2){
                    num++;c[y-1]=c[y]=0;
                    f[cur].insert(encode(),ans);
                }
            }
            else{
                f[cur].insert(encode(),f[cur^1].ans[k]);
                if(o(x+1,y)&&o(x,y+1)){
                    c[y-1]=c[y]=6;
                    f[cur].insert(encode(),ans);
                }
                if(num<2){
                    num++;
                    if(o(x+1,y)){
                        c[y-1]=6;c[y]=0;
                        f[cur].insert(encode(),ans);
                    }
                    if(o(x,y+1)){
                        c[y-1]=0;c[y]=6;
                        f[cur].insert(encode(),ans);
                    }
                }
            }
        }
    }
                    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&map[i][j]);
        int cur=0;f[0].init();f[0].insert(0,0);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                f[cur^=1].init();solve(cur,i,j);
            }
            for(int j=1;j<=f[cur].tot;j++){
                int num=f[cur].state[j]&7;
                f[cur].state[j]=((f[cur].state[j]>>6)<<3)|num;//
            }
        }
        ll ANS=-1ll<<60;
        for(int i=1;i<=f[cur].tot;i++){
            if((f[cur].state[i]&7)==2)ANS=max(ANS,f[cur].ans[i]);
        }
        printf("%lld",ANS);
        return 0;
    }
    View Code

    注意桶数组vis开成int类型,奇怪的问题一定是数组空间的问题。

  • 相关阅读:
    Java lambda 表达式
    c++第五天:默认初始化
    c++第四天
    质量评估面面观--聊一聊软件上线前的质量评估
    用script标签加载
    实现自己的前端模板轻量级框架
    事务消息中心-TMC
    Win10应用设计的那些事儿
    考拉定时任务框架kSchedule
    如何玩转基于风险的测试
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8819234.html
Copyright © 2020-2023  润新知