【Luogu】P4363一双木棋(状压爆搜)

  题目链接

  唉,只有AC了这道题才会感叹考场上没有想出解法的我是多么智障。

  我甚至连任何想法都没有。

  天啊我当时到底在想些什么。

  AC这道题我就能进前15了诶。

  我们发现只要确定了轮廓线那么此时的状态就是唯一的。

  那么,用15进制的状态去表示一下此时的轮廓线。详细说来,就是我们有n个数,第i个数表示第i行放了多少棋子,然后我们把这n个数用15进制表示一下(为什么不是m+1进制呢?qwq因为15进制写着方便),就可以爆搜啦

  然后因为开O2的关系,map记忆化一下就可以A啦

  

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<map>
#define maxs 30000020
#define maxn 120
#define mod 15
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

map<long long,long long>s;

long long q[maxn][maxn];

long long f[maxs][2];
bool vis[maxs];
long long tot;
long long End;
long long n,m;
long long mul[maxn];

inline void check(long long state){    if(s.count(state)==0)    s[state]=++tot;    }

void output(long long ret){
    for(long long i=1;i<=n;++i){
        printf("%lld ",ret%15);
        ret/=15;
    }
    printf("
");
    return;
}

void dfs(long long state){
    //output(state);
    check(state);
    if(vis[s[state]])    return;
    vis[s[state]]=1;
    long long &beta=f[s[state]][0],&alpha=f[s[state]][1];
    if(state==End)    return;
    beta=0x7fffffff;
    long long ret=state,last=m;
    
    for(long long i=1;i<=n;++i){
        long long now=ret%mod;
        if(now<last){
            long long nxt=state-((state/mul[i-1])%mod)*mul[i-1];
            nxt+=(now+1)*mul[i-1];
            //output(state);
            //output(nxt);
            //printf("%d
",now);
            dfs(nxt);
            beta=min(beta,f[s[nxt]][1]);
            alpha=max(alpha,f[s[nxt]][0]+q[i][now+1]);
        }
        last=now;
        ret/=mod;
    }
    //output(state);
    //printf("%lld %lld
",alpha,beta);
    //printf("
");
    return;
}

int main(){
    n=read(),m=read();
    mul[0]=1;
    for(long long i=1;i<=n;++i)    mul[i]=mul[i-1]*mod;
    long long ans=0;
    for(long long i=1;i<=n;++i)
        for(long long j=1;j<=m;++j)    q[i][j]=read();
    for(long long i=1;i<=n;++i)
        for(long long j=1;j<=m;++j){
            long long x=read();
            ans-=x;
            q[i][j]+=x;
        }
    for(long long i=1;i<=n;++i)    End=(End*mod)+m;
    dfs(0);
    printf("%lld",f[s[0]][1]+ans);
    return 0;
}
原文地址:https://www.cnblogs.com/cellular-automaton/p/8776101.html