简单DP,N×M的网格其中有一条边坏掉了,问从起点到终点的放法数
有两种方法,一种是DP很好理解
//#define LOCAL
#include <cstdio>
#include <cstring> int dp[][];
bool flag[][]; int main(void)
{
#ifdef LOCAL
freopen("2125in.txt", "r", stdin);
#endif int r, c;
while(scanf("%d%d", &r, &c) == )
{
int y1, x1, y2, x2;
scanf("%d%d%d%d", &y1, &x1, &y2, &x2);
dp[][] = ;
memset(flag, false, sizeof(flag));
flag[x1+][y1+] = flag[x2+][y2+] = true;
for(int i = ; i <= r; ++i)
for(int j = ; j <= c; ++j)
{
dp[i][j] = dp[i-][j] + dp[i][j-];
if(flag[i][j])
{
if(flag[i][j-])
dp[i][j] -= dp[i][j-];
if(flag[i-][j])
dp[i][j] -= dp[i-][j];
}
}
printf("%d\n", dp[r][c]);
}
return ;
}
代码君
第二种,用数学公式
如果没有坏边的话,总放法数是CN-1(M+N-2)
因为每种方法都要走(M+N-2)步,向上走N-1步,向下走M-1步
现在考虑一条坏边,那么就计算经过这条坏边的方案数然后从总数里面减去即可
经过坏边的放法数就是从起点到(x1, y1)的放法数×从(x2, y2)到终点的放法数
#define LOCAL
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std; long long c(long long m, long long n)
{
if(m== || n==)
return ;
n = min(n, m-n);
long long ans = ;
for(int i = ; i < n; ++i)
ans = ans * (m-i) / (+i);
return ans;
} int main(void)
{
#ifdef LOCAL
freopen("2125in.txt", "r", stdin);
#endif int n, m;
while(scanf("%d%d", &n, &m) == )
{
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
if(x1+y1 > x2+y2)
{
int t = x1;
x1 = x2, x2 = t;
t = y1;
y1 = y2, y2 = t;
}
printf("%lld\n", c(m+n-, m-) - c(x1+y1, x1) * c(m+n--x2-y2, m--x2));
}
return ;
}
代码君