P3190 [HNOI2007]神奇游乐园
[HNOI2007]神奇游乐园
题目描述
经历了一段艰辛的旅程后,主人公小 P 乘坐飞艇返回。在返回的途中,小 P 发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼。往下仔细一看,才发现这是一个游乐场,专为旅途中疲惫的人设计。
娱乐场可以看成是一块大小为
然而,小 P 并不喜欢其中的所有娱乐项目,于是,他给每个项目一个满意度。满意度为正时表示小 P 喜欢这个项目,值越大表示越喜欢。为负时表示他不喜欢,这个负数的绝对值越大表示他越不喜欢。为
小 P 决定将飞艇停在某个小格中,然后每步他可以移动到相邻的上下左右四个格子的某个格子中。
小 P 希望找一条路径,从飞艇所在格出发,最后又回到这个格子。
小 P 有一个习惯,从不喜欢浪费时间。因此,他希望经过每个格子都是有意义的:他到一个地方后,就一定要感受以下那里的惊险和刺激,不管自己是不是喜欢那里的娱乐项目。而且,除了飞艇所在格,其他的格子他不愿意经过两次。小 P 希望自己至少要经过四个格子。
在满足这些条件的情况下,小 P 希望自己玩过的娱乐项目的满意度之和最高。你能帮他找到这个最高的满意度之和吗?
输入格式
第一行为两个正整数
接下来的
输出格式
仅一行为一个整数,表示最高的满意度之和。
样例 #1
样例输入 #1
4 4
100 300 -400 400
-100 1000 1000 1000
-100 -100 -100 -100
-100 -100 -100 1000
样例输出 #1
4000
提示
数据规模与约定
对于
Solution
可以说是模板题的另一种形式了,做法基本和模板题一致,只有少部分地方需要更改。如果你对插头 DP 还不熟,那写一写这道题也是个不错的选择(插头 DP 的黑题还是有很多水题的)(推销下我写的插头DP的博客)。
与模板题不同的是,此题的回路并不要求走完整个方格图,这也就是说每个格子具有的插头可能有
此题解使用括号表示法,如果不会的话上面的博客链接有请。
分类讨论
1. 没有左插和上插
此种情况下,当前格子可以没有任何插头(也就是说不走这个格子),也可以同时具有右插和下插(作为一条路径的拐点):
或者是
2. 只有左插
此时当前格子可以有一个下插或者右插:
或者是
此时的右插或下插应该与左插的编号保持一致。
3. 只有下插
与上述情况几乎相同,就不详细再写了。
4. 左插上插都为
如果把 ,草稿纸的功能可比这玩意多多了)。
5. 左插上插都为
与上面的那种情况也是类似的,需要将当前的两个插头删除,然后找到左插对应的
6. 左插为 ,上插为
当前格子的插头刚好是能让两条路径一进一出的接上,所以直接删除这两个插头就可以了(我把
7. 左插为 ,上插为
既然这条路径都能向上走了,那么肯定就会构成回路了,所以此时更新答案:
因为在写这篇代码的时候直接套用了模板题的思路和代码,所以使用了哈希来优化状态数,但是实际上 (所以我就把哈希的模写成了与数组长度相等)。需要注意的是上面分类讨论的时候的转移是需要进行一定的判断的(判断新的状态是否合法,比如插头是否插到方格图外面去了这种情况),因为使用了哈希,如果出现了非法情况,那么之后会再在这些非法情况上生成新的非法情况,会导致 RE
或者是 TLE
(这两者的区别取决于你的数组开了多大,太大就会超时,太小就会运行时错误)。如果判断了非法情况的话,数组可以开的非常小(实测出来大概只有
Code
代码细节其实和模板题需要注意的几乎一致,所以就不再讲解了。
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof a)
#define int long long
using namespace std;
void read(auto &k)
{
k=0;auto flag=1;char b=getchar();
while (!isdigit(b)) {flag=(b=='-')?-1:1;b=getchar();}
while (isdigit(b)) {k=k*10+b-48;b=getchar();}
k*=flag;
}
void write(auto k) {if (k<0) {putchar('-'),write(-k);return;}if (k>9) write(k/10);putchar(k%10+48);}
void writewith(auto k,char c) {write(k);putchar(c);}
int n,m,a[105][105],Fans=INT_MIN;
int pre=1,cur=0;
const int _SIZE=200,HSIZE=200;
int f[2][_SIZE+5],state[2][_SIZE+5],tot[2],bits[15];
struct HASH{
int nxt,to;
}H[_SIZE+5];
int ptr[HSIZE+5],at;
void modify(int sta,int val)
{
int key=sta%HSIZE;
for (int i=ptr[key];i;i=H[i].nxt)
if (state[cur][H[i].to]==sta)
{
f[cur][H[i].to]=max(f[cur][H[i].to],val);
return;
}
tot[cur]++;if (tot[cur]>_SIZE) printf("?"),exit(0);//这一句类似于assert,只不过是想看测试点RE的原因
state[cur][tot[cur]]=sta;
f[cur][tot[cur]]=val;
H[++at].nxt=ptr[key];
H[at].to=tot[cur];
ptr[key]=at;
}
void init(){for (int i=1;i<=10;i++) bits[i]=i<<1;}
void PlugDP()
{
tot[cur]=1;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=tot[cur];j++) state[cur][j]<<=2;
for (int j=1;j<=m;j++)
{
swap(cur,pre);
tot[cur]=0;at=0;mem(ptr,0);
for (int k=1;k<=tot[pre];k++)
{
int nowans=f[pre][k],nowsta=state[pre][k];
int isR=(nowsta>>bits[j-1])%4,isD=(nowsta>>bits[j])%4;
if ((!isR) && (!isD))
{
if (j!=m && i!=n) modify(nowsta+(1<<bits[j-1])+2*(1<<bits[j]),nowans+a[i][j]);
modify(nowsta,nowans);
}
else if ((!isR) && isD)
{
if (j!=m) modify(nowsta,nowans+a[i][j]);
if (i!=n) modify(nowsta-isD*(1<<bits[j])+isD*(1<<bits[j-1]),nowans+a[i][j]);
}
else if (isR && (!isD))
{
if (i!=n) modify(nowsta,nowans+a[i][j]);
if (j!=m) modify(nowsta-isR*(1<<bits[j-1])+isR*(1<<bits[j]),nowans+a[i][j]);
}
else if (isR==1 && isD==1)
{
int cnt=1;
for (int l=j+1;l<=m;l++)
{
if ((nowsta>>bits[l])%4==1) cnt++;
else if ((nowsta>>bits[l])%4==2) cnt--;
if (!cnt)
{
modify(nowsta-(1<<bits[j-1])-(1<<bits[j])-(1<<bits[l]),nowans+a[i][j]);
break;
}
}
}
else if (isR==2 && isD==2)
{
int cnt=1;
for (int l=j-2;l;l--)
{
if ((nowsta>>bits[l])%4==1) cnt--;
else if ((nowsta>>bits[l])%4==2) cnt++;
if (!cnt)
{
modify(nowsta-2*(1<<bits[j-1])-2*(1<<bits[j])+(1<<bits[l]),nowans+a[i][j]);
break;
}
}
}
else if (isR==2 && isD==1)
modify(nowsta-(1<<bits[j])-2*(1<<bits[j-1]),nowans+a[i][j]);
else if (isR==1 && isD==2 && 2*(1<<bits[j])+(1<<bits[j-1])==nowsta)
Fans=max(Fans,nowans+a[i][j]);
}
}
}
}
signed main()
{
read(n),read(m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) read(a[i][j]);
init();
PlugDP();
writewith(Fans,'\n');
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步