题目描述
给定 n 行,m 列的网格。第i行第j个格子上面写有两个数字 A[i][j] 和 B[i][j] 。
邱宇将从左上角走到右下角(第一行第一列走到第n行第m列),每次只能往下走一行或者往右走一格且不能走出去。在每一个格子上,他将给A[i][j]和B[i][j]一个涂成红色,另一个填黑色。
在所有有可能的路径与涂色方案中,abs(黑色数字之和-红色数字之和)最小是多少?
输入
第一行两个正整数表示行和列n,m
接下来n行,每行m个数表示格子上的数字A[i][j]
接下来又有n行,每行m个数表示格子上的数字B[i][j]
数据保证2 <= n,m <= 80,0 <= A[i][j], B[i][j] <= 80
输出
输出最小的两种颜色数字之和的差值。
样例输入
样例输入1:
2 2
1 2
3 4
3 4
2 1
样例输入2:
2 3
1 10 80
80 10 1
1 2 3
4 5 6
样例输出
样例输出1:
0
样例输出2:
2
题解
#include<bits/stdc++.h>
using namespace std;
bool dp[81][81][25601];
int h,w;
int a[85][85],b[85][85],c[85][85];
int sum;
int main()
{
cin>>h>>w;
for(int i=1;i<=h;++i)
{
for(int j=1;j<=w;++j)
{
cin>>a[i][j];
sum=max(sum,a[i][j]);
}
}
for(int i=1;i<=h;++i)
{
for(int j=1;j<=w;++j)
{
cin>>b[i][j];
c[i][j]=a[i][j]-b[i][j];
}
}
//初始值
dp[1][1][c[1][1]+12800]=1;
dp[1][1][-c[1][1]+12800]=1;
for(int i=1;i<=h;++i)
{
for(int j=1;j<=w;++j)
{
for(int k=0;k<=sum*(h+w-1);++k)
{
//状态转移,记得加上 12800
dp[i][j][k+12800]|=dp[i-1][j][k+c[i][j]+12800]|dp[i-1][j][k-c[i][j]+12800];
dp[i][j][k+12800]|=dp[i][j-1][k+c[i][j]+12800]|dp[i][j-1][k-c[i][j]+12800];
dp[i][j][-k+12800]|=dp[i-1][j][-k+c[i][j]+12800]|dp[i-1][j][-k-c[i][j]+12800];
dp[i][j][-k+12800]|=dp[i][j-1][-k+c[i][j]+12800]|dp[i][j-1][-k-c[i][j]+12800];
}
}
}
for(int i=0;i<=sum*(h+w-1);++i)
{
if(dp[h][w][i+12800]||dp[h][w][-i+12800])
{
//找到最小的k的值
cout<<i<<endl;
return 0;
}
}
return 0;
}
很简单的入门题
动态规划 dp。
我们定义 dp[i][j][k] 表示到达 i,j 点是否可以做到 涂成红色减去涂成蓝色得数的值 为 k,可以做到则为 11,不可以做到就是 00。然后我们在定义一个 c[i][j] 表示 a[i][j]−b[i][j]。
显然,我们可以得到两种大的情况。
第一种,从i−1,j 走过来,则此时可以得到转移方程为 dp[i][j][k]∣=dp[i−1][j][k−c[i][j]]∣dp[i−1][j][k+c[i][j]]。
第二种,从 i,j−1 走过来,则此时同上,可以得到转移方程为 dp[i][j][k]∣=dp[i][j−1][k−c[i][j]]∣dp[i][j−1][k−c[i][j]]。
但是这个地方我们从要注意一种情况,就是有可能这个值为负数,所以,我们可以将所有的数组多开一倍,然后我们将所有的 k 加上一个 1280012800,就不会存在有负数的情况了。