题解 洛谷P1958 【上学路线】
言归正传,闲言少叙,现在进入题目吧!
题目大意:
现在有一张地图,你要从坐标(1,1)处(左下角)走到坐标(n,m)处(右上角),中间有一些地方不能走,而且只允许向上或向右走。求一共有多少种走法?
乍一看题目,嗯,不怎么难,显然是一道动态规划(大佬们都称之为DP)题。那么,我们首先要考虑的,就是dp[i][j]表示什么。
对于巨佬来说是很简单的吧?
很容易想到,我们可以用dp[i][j]表示走到坐标(i,j)有多少种方案。
那么,最后要求的就是dp[n][m]。
1.初始化
dp[1][1]自然等于1。不知道的请回吧
正常情况下,dp[i][1]=1,dp[1][i]=1。
不过请注意:
有坑!!
如果a[i][1]不能行驶,那么它这个点(dp[i][1]),以及后面的(dp[i+1][1],dp[i+2][1]……)都无法走到0。
2.状态转移方程
分类讨论。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
if(dp[i][j]==-1) { continue;//此点不必运算 } if(dp[i-1][j]==-1&&dp[i][j-1]==-1) { dp[i][j]=-1;//此点不可能走到 } if(dp[i-1][j]==-1&&dp[i][j-1]!=-1) { dp[i][j]=dp[i][j-1]; } if(dp[i][j-1]==-1&&dp[i-1][j]!=-1) { dp[i][j]=dp[i-1][j]; } if(dp[i][j-1]!=-1&&dp[i-1][j]!=-1) { dp[i][j]=dp[i-1][j]+dp[i][j-1]; } //后三种是常规状态,即dp[i][j]就是从下边和左边来的,如果一边来不了,就只算另一边。
3.上代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; int dp[17][17]; int main() { int i,j; int n,m; cin>>n>>m; int q; cin>>q; for(i=1;i<=q;i++) { int tx,ty; cin>>tx>>ty; dp[tx][ty]=-1; } dp[1][1]=1; for(i=1;i<=n;i++) { if(dp[i][1]!=-1) { dp[i][1]=1; } else { break; } } for(i=1;i<=m;i++) { if(dp[1][i]!=-1) { dp[1][i]=1; } else { break; } } for(i=2;i<=n;i++) { for(j=2;j<=m;j++) { if(dp[i][j]==-1) { continue; } if(dp[i-1][j]==-1&&dp[i][j-1]==-1) { dp[i][j]=-1; } if(dp[i-1][j]==-1&&dp[i][j-1]!=-1) { dp[i][j]=dp[i][j-1]; } if(dp[i][j-1]==-1&&dp[i-1][j]!=-1) { dp[i][j]=dp[i-1][j]; } if(dp[i][j-1]!=-1&&dp[i-1][j]!=-1) { dp[i][j]=dp[i-1][j]+dp[i][j-1]; } } } cout<<dp[n][m]<<endl; return 0; }
无注释版,有注释版在模块2当中。
点个赞再走吧!
#include<bits/stdc++.h>
using namespace std;
int dp[17][17];
int main()
{
int i,j;
int n,m;
cin>>n>>m;
int q;
cin>>q;
for(i=1;i<=q;i++)
{
int tx,ty;
cin>>tx>>ty;
dp[tx][ty]=-1;
}
dp[1][1]=1;
for(i=1;i<=n;i++)
{
if(dp[i][1]!=-1)
{
dp[i][1]=1;
}
else
{
break;
}
}
for(i=1;i<=m;i++)
{
if(dp[1][i]!=-1)
{
dp[1][i]=1;
}
else
{
break;
}
}
for(i=2;i<=n;i++)
{
for(j=2;j<=m;j++)
{
if(dp[i][j]==-1)
{
continue;
}
if(dp[i-1][j]==-1&&dp[i][j-1]==-1)
{
dp[i][j]=-1;
}
if(dp[i-1][j]==-1&&dp[i][j-1]!=-1)
{
dp[i][j]=dp[i][j-1];
}
if(dp[i][j-1]==-1&&dp[i-1][j]!=-1)
{
dp[i][j]=dp[i-1][j];
}
if(dp[i][j-1]!=-1&&dp[i-1][j]!=-1)
{
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
}
cout<<dp[n][m]<<endl;
return 0;
}
不要妄图追上西坠的太阳,而是要在黎明前就等着它!