【题意】给定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类型,奇怪的问题一定是数组空间的问题。

最新文章

  1. java线程(2016-4-7)
  2. linux常用的命令
  3. Java -- 子类使用super调用父类的方法A,A 调用了方法B,子类也override方法B,那么super.A()最终调用到了子类的B方法
  4. 模式窗口刷新不弹出新窗口触发NET事件
  5. c# 串口编程
  6. zabbix网络发现
  7. SSIS -&gt;&gt; Error Handling
  8. BZOJ 1589 采集糖果
  9. gcc中__attribute__ ((constructor(101)))做成.a库成功链接
  10. 你不能错过.net 并发解决方案
  11. jquery.qrcode.js 生成二维码并支持中文的方法
  12. [转]python3之日期和时间
  13. SolrCloud集群搭建(基于zookeeper)
  14. 遇到了IE10不能登录的问题,很早就有解决方案了
  15. web前端读取文本文件内容
  16. 阿里云RDS上的一些概念性记录
  17. Java8 FutureTask 分析
  18. 【转】 Pro Android学习笔记(二二):用户界面和控制(10):自定义Adapter
  19. Linux下监视GPU、CPU的使用情况
  20. MySQL入门笔记 - 数据类型

热门文章

  1. Docker的volume机制实现容器数据的持久性存储
  2. selenium获取新页面标签页(只弹出一个新页面的切换)
  3. 弱智python小游戏猜数字
  4. html template &amp; iframe
  5. BZOJ5322 JXOI2018排序问题
  6. BZOJ5120 无限之环(费用流)
  7. P1155 双栈排序
  8. PHP 字符串数组按照拼音排序的问题
  9. 【BZOJ4804】欧拉心算
  10. BZOJ2217 [Poi2011]Lollipop 【贪心】