小象和老鼠 DP

小象和老鼠 DP

\(N*M\)的网格图,格子\((i,j)\)有\(A_{i,j}\)个老鼠,问小象从左上角\((1,1)\)走到右下角\((N,M)\)看到的最少老鼠。小象可以看见老鼠,当且仅当老鼠的位置\((x2,y2)\)满足\(|x1-x2|+|y1-y2|\le1\)。

比较有意思的一道DP题,还是比较简单。我们发现如果直接设\(f[i][j]\)跑会导致一些格子重复计算,所以我们可以设\(f[i][j][0]\)表示到位置\((i,j)\)时最少看到的老鼠数量,并且当前状态是从上面转移而来的,\(f[i][j][1]\)表示到位置\((i,j)\)时最少看到的老鼠数量,并且当前状态是从左面转移而来的,这样我们便可以获得决策所需要的全部条件,从而避免重复计算。

转移方程看着图写就好了

//f[i][j][0]当前状态从上面转移而来
f[i][j][0]=min(f[i-1][j][1]+mp[i][j+1]+mp[i+1][j], f[i][j][0]);
f[i][j][0]=min(f[i-1][j][0]+mp[i+1][j]+mp[i][j-1]+mp[i][j+1], f[i][j][0]);
//f[i][j][0]当前状态从左面转移而来
f[i][j][1]=min(f[i][j-1][1]+mp[i][j+1]+mp[i-1][j]+mp[i+1][j], f[i][j][1]);
f[i][j][1]=min(f[i][j-1][0]+mp[i][j+1]+mp[i+1][j], f[i][j][1]);

完整代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 1010
using namespace std;
int f[MAXN][MAXN][2],mp[MAXN][MAXN];
int n,m;
int calc(int x, int y){
    int res=0;
    if(x+1>=1&&x+1<=n) res+=mp[x+1][y];
    if(x-1>=1&&x-1<=n) res+=mp[x-1][y];
    if(y+1>=1&&y+1<=m) res+=mp[x][y+1];
    if(y-1>=1&&y-1<=m) res+=mp[x][y-1];
    return res+mp[x][y];
}
int main(){
    scanf("%d %d", &n, &m);
    for(int i=0;i<=n;++i)
    for(int j=0;j<=m;++j)
        f[i][j][0]=f[i][j][1]=0x3f3f3f3f;
    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
        scanf("%d", &mp[i][j]);
    f[1][1][0]=f[1][1][1]=calc(1, 1);
    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j){
        //f[i][j][0]当前状态从上面转移而来
        f[i][j][0]=min(f[i-1][j][1]+mp[i][j+1]+mp[i+1][j], f[i][j][0]);
        f[i][j][0]=min(f[i-1][j][0]+mp[i+1][j]+mp[i][j-1]+mp[i][j+1], f[i][j][0]);
        //f[i][j][0]当前状态从左面转移而来
        f[i][j][1]=min(f[i][j-1][1]+mp[i][j+1]+mp[i-1][j]+mp[i+1][j], f[i][j][1]);
        f[i][j][1]=min(f[i][j-1][0]+mp[i][j+1]+mp[i+1][j], f[i][j][1]);
    }
    printf("%d", min(f[n][m][0], f[n][m][1]));
    return 0;
}

这是校内模拟赛做的一道题,一开始以为是道DP签到题导致思路都错了,后面静下心慢慢分析决策才想出正解,可见手推样例重要性。另外一定不要轻敌。

原文地址:https://www.cnblogs.com/santiego/p/11563826.html

时间: 2024-08-12 14:15:17

小象和老鼠 DP的相关文章

hdu2067 小兔的棋盘 DP/数学/卡特兰数

棋盘的一角走到另一角并且不越过对角线,卡特兰数,数据量小,可以当做dp求路径数 1 #include<stdio.h> 2 long long a[36][36]; 3 int main() 4 { 5 int n,count=0; 6 while (scanf("%d",&n)!=EOF&&n!=-1) 7 { 8 int i,j; 9 long long s; 10 count++; 11 for (i=1;i<=n;i++) a[0][i

「HZOI 2016」小象和老鼠

Description S 国的动物园是一个N*M的网格图,左上角的坐标是(1,1),右下角的坐标是(N,M).小象在动物园的左上角,它想回到右下角的家里去睡觉,但是动物园中有一些老鼠,而小象又很害怕老鼠.动物园里的老鼠是彼此互不相同的.小象的害怕值定义为他回家的路径上可以看见的不同的老鼠的数量.若小象当前的位置为(x1,y1),小象可以看见老鼠,当且仅当老鼠的位置(x2,y2)满足|x1-x2|+|y1-y2|<=1 .由于小象很困了,所以小象只会走一条最近的路回家,即小象只会向下或者向右走.

【上海交大oj】邮递员小F(状态压缩dp)(旅行商问题)

1088. 邮递员小F Description 因为制造类专业很难在大城市立足,曾经立志振兴中华之工业的小F,果断在本科毕业后转行做了一名光荣的邮递员. 他的任务是每天从总局出发,行走于所管辖区域的若干的邮局,收集所有的信,然后再汇总返回总局. 因为工作繁忙,同一个邮局他每天只希望去一次. 来往于任意两个邮局是有一定代价的.而且为了方便统计,假定来回两条道路上的代价假设是一样的. 现在小F希望你能给出他每天的最优行走方案,使得总的代价最少. Input Format 输入数据包括两部分. 第一行

洛谷 p1164 小A点菜 【dp(好题)】 || 【DFS】

题目链接:https://www.luogu.org/problemnew/show/P1164 题目背景 uim神犇拿到了uoi的ra(镭牌)后,立刻拉着基友小A到了一家--餐馆,很低端的那种. uim指着墙上的价目表(太低级了没有菜单),说:"随便点". 题目描述 不过uim由于买了一些辅(e)辅(ro)书,口袋里只剩M元(M<=10000). 餐馆虽低端,但是菜品种类不少,有N种(N<=100),第i种卖ai元(ai<=1000).由于是很低端的餐馆,所以每种菜

小象涂色 [DP]

小象涂色题目描述:( elephant.pas/.c/.cpp )时间限制: 1s ,空间限制 128MB小象喜欢为箱子涂色.小象现在有 c 种颜色,编号为 0~c-1 ;还有 n 个箱子,编号为1~n ,最开始每个箱子的颜色为 1 .小象涂色时喜欢遵循灵感:它将箱子按编号排成一排,每次涂色时,它随机选择 [L , R] 这个区间里的一些箱子(不选看做选 0 个),为之涂上随机一种颜色.若一个颜色为 a 的箱子被涂上 b 色,那么这个箱子的颜色会变成( a*b ) modc .请问在 k 次涂色

JZYZOJ1384 种花小游戏 状压dp

http://172.20.6.3/Problem_Show.asp?id=1384 最开始以为是dfs然后超时了,然后调了半天调成dp,还不如再写一遍... 代码 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const int maxn=1&

Codeforces 148D 一袋老鼠 Bag of mice | 概率DP 水题

除非特别忙,我接下来会尽可能翻译我做的每道CF题的题面! Codeforces 148D 一袋老鼠 Bag of mice | 概率DP 水题 题面 胡小兔和司公子都认为对方是垃圾. 为了决出谁才是垃圾,大哥拿来了一袋老鼠,其中有w只白老鼠和b只黑老鼠.胡小兔先抓,先抓到白老鼠的人赢. 每次学姐抓完老鼠之后,总会有另外一只老鼠从袋子里自己跑出来(这只老鼠不算任何人抓的),而胡小兔抓老鼠时则不会发生这样的事. 每次袋子里的每只老鼠被抓到的概率相等,当有一只老鼠跑出来的时候,每只老鼠跑出来的几率也相

hdu 4521 小明系列问题——小明序列(线段树+DP或扩展成经典的LIS)

小明系列问题--小明序列 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 1553    Accepted Submission(s): 457 Problem Description 大家都知道小明最喜欢研究跟序列有关的问题了,但是也就由于这样,小明差点儿已经玩遍各种序列问题了.可怜的小明苦苦地在各大站点上寻找着新的序列问题,但是找来

UVA-10271 Chopsticks (线性DP)

题目大意:在n个数中,找出k个三元组(a<=b<=c),求最小的(a-b)*(a-b)之和. 题目分析:将所有数从大到小排序,定义dp(i,j)表示前 i 个数中找出 j 个三元组时的最小和,则状态转移方程为dp(i,j)=min(dp(i-1,j),dp(i-2,j-1)),第二种决策是在前i-1个数构成j-1组三元组时必须还要有剩余的数的前提下才能做出.这道题和“搬寝室”和“筷子”类似,同样要填表求解并且注意边界. 代码如下: # include<iostream> # inc