清橙网A1110. 街道

来源:互联网 发布:it服务 软件 编辑:程序博客网 时间:2024/06/10 07:13

试题来源

  NOIP1997 普及组

问题描述

设有一个N*M(l≤ N≤50, l≤ M≤ 50)的街道。n和m表示横竖街道数。
规定行人从A(1,1)出发,在街道上只能向东或北方向行走。
N=3,M=3的街道图,从A出发到达B共有6条可供行走的路。
若在N*M的街道中,设置一个矩形障碍区域(包括围住该区域的街道和点)不让行人通行。
此矩形障碍区域用2对顶点坐标给出,前图中的2对顶点坐标为:(2,2),(8,4),此时从 A出发到达B的路径仅有两条。

程序要求:

任务一:给出N,M后,求出所有从A出发到达B的路径的条数。

任务二:给出N,M,同时再给出此街道中的矩形障碍区域的2对顶点坐标(X1,y1), (X2,Y2),然后求出此种情况下所有从A出发到达B的路径的条数。
如果答案太大,输出最后20位。

输入格式

第一行两个数n和m。
第二行为X1,Y1,X2,Y2.如果是任务一,则第二行为4个0.

输出格式

输出走路方案数。

样例输入

3 3
0 0 0 0

样例输出

6

样例输入

50 50
2 2 49 49
样例输出
2

数据规模和约定

  1<=N,M<=50
 
#include<cstdio>#include<algorithm>#define maxn 60#define l 10000000000using namespace std;struct number{ long long d1,d2; //存储方案的后20位 }f[maxn][maxn];int n,m;int flag[maxn][maxn]; //障碍标记 void start(){ long long s;  f[1][1].d1=1;f[1][1].d2=0; for(int k=3;k<=m+n;k++) for(int i=1;i<=n;i++){ if(k-i>=1&&k-i<=m&&!flag[i][k-i]){ int j=k-i; if(j-1>=1) f[i][j]=f[i][j-1]; //将前一项给后一项赋值  if(i-1>=1){ //将前一项的值相加  s=f[i][j].d1+f[i-1][j].d1; f[i][j].d1=s%l; f[i][j].d2=(f[i-1][j].d2+f[i][j].d2+s/l)%l; } } } if(f[n][m].d2==0) printf("%I64d\n",f[n][m].d1); else printf("%I64d%010I64d\n",f[n][m].d2,f[n][m].d1); //对前十位不足的用0填充 }int main(){ int x1,x2,y1,y2; scanf("%d%d",&n,&m); scanf("%d%d%d%d",&x1,&y1,&x2,&y2); if(x1>x2) swap(x1,x2); //对障碍的 起始点进行转换  if(y1>y2) swap(y1,y2); for(int i=x1;i<=x2;i++) for(int j=y1;j<=y2;j++) flag[i][j]=1; //对障碍进行标记  start(); return 0; }

表示智商太低,看了好久才看懂。

将方法种数的前十位和后十位分别用d1,d2存起来,这样就不要用高精度了。

初始在(1,1)的位置,然后第一步走出的位置可以为:(1,2)、(2,1),其坐标之和为3
   以此类推,第二步到达的点坐标之和为4,第三步到达的点坐标之和为5。
f[i][j]表示从起点到达(i,j)的方案数,则有:f[i][j]=f[i-1][j]+f[i][j-1];
   flag[i][j]表示(i,j)点能否通过。
   于是得到递推式:
   for(k=3;k<=n+m;k++)
    for(i=1;i<=n;i++)
     {
      j=k-i;
      f[i][j]=f[i-1][j]+f[i][j-1];
     }
   当然,还要保证上述的点都是有效的,能通过的。
这是参考的原文链接noip1997街道
0 0