这是来自Topcoder的一道动态规划有关的题目,原文如下:
https://community.topcoder.com/stat?c=problem_statement&pm=1889&rd=4709&rm=&cr=152347
本题大意是在直角坐标系中,从(0,0)到(width, height)有几种不同的走法,其中路径长必须为width+height,另外,还有一些相邻点之间不可达的路径。如不可达路径是(a b c d),意思是点(a, b)与(c,d)之间不可达。
如下输入:
6 /注:width/
6 /注:height/
{“0 0 0 1”,”6 6 5 6”}
输出:
252
问题分析求解:
因为从(0, 0)到(width, height)的路径长必须为width+heght,所以对于一个点来说它的选择只有向上或向右。因为只有这样width+height才有可能。对于动态规划问题有两个关键的问题:怎么定义状态,及状态转移方程。我们这里假设r(x,y)为点(0, 0)到(x, y)的路径总数。则状态转移方程:
r(x, y) = r(x - 1, y) + r(x, y - 1) (其中 x > 0, y > 0)
r(x, y) = r(x - 1, 0) (其中 x > 0, y = 0)
r(x, y) = r(0, y)(其中x =0 y > 0)
此时很容易编码。
程序源码(c++):
#include <iostream>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
using namespace std;
class AvoidRoads
{
public:
long long numWays(int width, int height, vector<string> &bad);
};
int main(void)
{
AvoidRoads l;
vector<string> str;
#if 0
str.push_back("0 3 0 2");
str.push_back("1 2 1 3");
str.push_back("2 2 2 3");
str.push_back("3 2 3 3");
str.push_back("4 2 4 3");
str.push_back("5 2 5 3");
str.push_back("6 2 6 3");
str.push_back("7 2 7 3");
str.push_back("8 2 8 3");
str.push_back("9 2 9 3");
#endif
str.push_back("0 0 0 1");
str.push_back("6 6 5 6");
cout << l.numWays(6, 6, str) << endl;
return 0;
}
long long AvoidRoads::numWays(int width, int height, vector<string> &bad)
{
long long D[width + 1][height + 1];
char is_bad1[128], is_bad2[128];
for(int i = 0; i <= width; i++)
{
for(int j = 0; j <= height; j++)
{
D[i][j] = -2;
}
}
for(int i = 0; i <= width; i++)
{
for(int j = 0; j <= height; j++)
{
if(i == 0 && j == 0)
{
D[0][0] = 1;
continue;
}
if(i != 0 && j == 0)
{
snprintf(is_bad1, sizeof(is_bad1), "%d %d %d %d", i - 1, j, i, j);
snprintf(is_bad2, sizeof(is_bad2), "%d %d %d %d", i, j, i - 1, j);
int p;
for(p = 0; p < bad.size(); p++)
{
if(bad[p] == string(is_bad1) || bad[p] == string(is_bad2))
{
break;
}
}
if((bad.size() != 0 && p != bad.size()) ||
D[i - 1][j] == -1)
{
D[i][j] = -1;
}
else if(D[i - 1][j] != -1)
{
D[i][j] = D[i - 1][j];
}
}
else if(i == 0 && j != 0)
{
snprintf(is_bad1, sizeof(is_bad1), "%d %d %d %d", i, j - 1, i, j);
snprintf(is_bad2, sizeof(is_bad2), "%d %d %d %d", i, j, i, j - 1);
int p;
for(p = 0; p < bad.size(); p++)
{
if(bad[p] == string(is_bad1) || bad[p] == string(is_bad2))
{
break;
}
}
if((bad.size() != 0 && p != bad.size()) ||
D[i][j - 1] == -1)
{
D[i][j] = -1;
}
else if(D[i - 1][j] != -1)
{
D[i][j] = D[i][j - 1];
}
}
else
{
int left = 1, down = 1;
snprintf(is_bad1, sizeof(is_bad1), "%d %d %d %d", i - 1, j, i, j);
snprintf(is_bad2, sizeof(is_bad2), "%d %d %d %d", i, j, i - 1, j);
int p;
for(p = 0; p < bad.size(); p++)
{
if(bad[p] == string(is_bad1) || bad[p] == string(is_bad2))
{
left = 0;
break;
}
}
snprintf(is_bad1, sizeof(is_bad1), "%d %d %d %d", i, j - 1, i, j);
snprintf(is_bad2, sizeof(is_bad2), "%d %d %d %d", i, j, i, j - 1);
for(p = 0; p < bad.size(); p++)
{
if(bad[p] == string(is_bad1) || bad[p] == string(is_bad2))
{
down = 0;
break;
}
}
if((left == 0 && down == 0) ||
(D[i - 1][j] == -1 && D[i][j - 1] == -1) ||
(left == 0 && D[i][j - 1] == -1) ||
(D[i - 1][j] == -1 && down == 0))
{
D[i][j] = -1;
}
else if(left == 0 || D[i - 1][j] == -1)
{
D[i][j] = D[i][j - 1];
}
else if(down == 0 || D[i][j - 1] == -1)
{
D[i][j] = D[i - 1][j];
}
else
{
D[i][j] = D[i - 1][j] + D[i][j - 1];
}
}
}
}
return D[width][height];
}