【题意】给定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=,MOD=,S=;
int n,m,map[][maxn],c[maxn],num;
struct h{
int first[MOD],nxt[S],state[S],tot;//
ll ans[S];
void init(){
memset(first,,sizeof(first));
tot=;
}
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[];
void decode(int x){num=x&;x>>=;for(int i=m;i>=;i--)c[i]=x&,x>>=;}
int vis[];//
int encode(){
for(int i=;i<=;i++)vis[i]=;
int cnt=,x=;
for(int i=;i<=m;i++){
if(!c[i]){x<<=;continue;}
if(!vis[c[i]])vis[c[i]]=++cnt;
x=(x<<)|vis[c[i]];
}
return x=(x<<)|num;
}
bool o(int x,int y){return x<=n&&y<=m;}
void solve(int cur,int x,int y){
for(int k=;k<=f[cur^].tot;k++){
decode(f[cur^].state[k]);
int left=c[y-],up=c[y];ll ans=f[cur^].ans[k]+map[x][y];
if(left&&up){
if(left!=up){
c[y-]=c[y]=;
for(int i=;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+,y)){
c[y-]=now;c[y]=;
f[cur].insert(encode(),ans);
}
if(o(x,y+)){
c[y-]=;c[y]=now;
f[cur].insert(encode(),ans);
}
if(num<){
num++;c[y-]=c[y]=;
f[cur].insert(encode(),ans);
}
}
else{
f[cur].insert(encode(),f[cur^].ans[k]);
if(o(x+,y)&&o(x,y+)){
c[y-]=c[y]=;
f[cur].insert(encode(),ans);
}
if(num<){
num++;
if(o(x+,y)){
c[y-]=;c[y]=;
f[cur].insert(encode(),ans);
}
if(o(x,y+)){
c[y-]=;c[y]=;
f[cur].insert(encode(),ans);
}
}
}
}
} int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)for(int j=;j<=m;j++)scanf("%d",&map[i][j]);
int cur=;f[].init();f[].insert(,);
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
f[cur^=].init();solve(cur,i,j);
}
for(int j=;j<=f[cur].tot;j++){
int num=f[cur].state[j]&;
f[cur].state[j]=((f[cur].state[j]>>)<<)|num;//
}
}
ll ANS=-1ll<<;
for(int i=;i<=f[cur].tot;i++){
if((f[cur].state[i]&)==)ANS=max(ANS,f[cur].ans[i]);
}
printf("%lld",ANS);
return ;
}
注意桶数组vis开成int类型,奇怪的问题一定是数组空间的问题。