动态规划法设计算法一般分成三个阶段:
(1)分段:将原问题分解为若干个相互重叠的子问题;
(2)分析:分析问题是否满足最优性原理,找出动态规划函数的递推式;
(3)求解:利用递推式自底向上计算,实现动态规划过程。
动态规划法利用问题的最优性原理,以自底向上的方式从子问题的最优解逐步构造出整个问题的最优解。
DP 就是要避免重复计算!
穿过街道
#include
using namespace std;
int f[100][100];
int getf(int x,int y)
{
if (f[x][y]!=-1)
return f[x][y];
int result;
if (x==0||y==0)
result=1;
else
result=getf(x-1,y)+getf(x,y-1);
f[x][y]=result;
return result;
}
int main()
{
int i,j,n;
memset(f,-1,sizeof(f));
while(cin>>n)
{
if (n==0)
break;
cout<<getf(n,n)<<endl;
}
return 0;
}
数字三角形
#include
using namespace std;
int main()
{
int data[102][102];
int inp[102][102];
int n;
while(cin>>n)
{
memset(inp,0,sizeof(inp));
memset(data,0,sizeof(data));
for(int i=1; i<=n; i++)
for(int j=1; j<=i; j++)
{
cin>>data[i][j];
if (i==1)
inp[i][j]=data[i][j];
else
inp[i][j]=max(inp[i-1][j],inp[i-1][j-1])+data[i][j];
}
int tmp=0;
for(int k=1; k<=n; k++)
if (tmp<=inp[n][k])
tmp=inp[n][k];
cout<<tmp<<endl;
}
return 0;
}
Function Run Fun
#include
using namespace std;
long long data[21][21][21];
long long inf(int x,int y,int z)
{
if (x<=0||y<=0||z<=0)
return 1;
if (x>20||y>20||z>20)
return inf(20,20,20);
if (x<y&&y<z)
{
if (data[x][y][z]==-1)
data[x][y][z]=inf(x,y,z-1)+inf(x,y-1,z-1)-inf(x,y-1,z);
return data[x][y][z];
}
else
{
if (data[x][y][z]==-1)
{
data[x][y][z]=inf(x-1,y,z)+inf(x-1,y-1,z)+inf(x-1,y,z-1)-inf(x-1,y-1,z-1);
}
return data[x][y][z];
}
}
int main()
{
int x,y,z;
while(cin>>x>>y>>z)
{
if (x==-1&&y==-1&&z==-1)
break;
memset(data,-1,sizeof(data));
cout<<"w("<<x<<", "<<y<<", "<<z<<")"<<" = "<<inf(x,y,z)<<endl;
}
return 0;
}
Recaman Sequence
#include
using namespace std;
#define size 500000
int data[size+1];
bool inp[size*10];
int main()
{
int n;
memset(inp,false,sizeof(inp));
data[0]=0;
inp[0]=true;
for(int i=1; i<=500000; i++)
{
if (data[i-1]-i>0&&inp[data[i-1]-i]==false)
data[i]=data[i-1]-i;
else
data[i]=data[i-1]+i;
inp[data[i]]=true;
}
while(cin>>n&&n!=-1)
{
cout<<data[n]<<endl;
}
return 0;
}
滑雪
#include
using namespace std;
int data[101][101];
int inp[101][101];
int m,n;
int f(int i,int j)
{
int max1,max2;
int max_right=0,max_left=0,max_up=0,max_down=0;
if (data[i][j]>0)
return data[i][j];
if (j+1<=n&&inp[i][j]>inp[i][j+1])
max_right=f(i,j+1);//右边
if (j-1>=1&&inp[i][j]>inp[i][j-1])
max_left=f(i,j-1);//左边
if (i+1<=m&&inp[i][j]>inp[i+1][j])
max_up=f(i+1,j);//上面
if (i-1>=1&&inp[i][j]>inp[i-1][j])
max_down=f(i-1,j);//下面
max1=max(max_right,max_left);
max2=max(max_up,max_down);
data[i][j]=max(max1,max2)+1;//4个方向上的最大值,记录下来
return data[i][j];
}
int main()
{
memset(data,0,sizeof(data));
int k,max_all;
while(cin>>m>>n)
{
max_all=0;
for(int i=1; i<=m; i++)
for(int j=1; j<=n; j++)
cin>>inp[i][j];
for(int i=1; i<=m; i++)
for(int j=1; j<=n; j++)
k=f(i,j);//可以优化,直接计算最大值
for(int i=1; i<=m; i++)
for(int j=1; j<=n; j++)
if (max_all<data[i][j])
max_all=data[i][j];
cout<<max_all<<endl;
}
return 0;
}
命运-dp
#include
using namespace std;
const int maxn = 25;
const int maxm = 1000;
int dp[maxn][maxm],a[maxn][maxm],u[maxn][maxm];
int n,m;
int dfs(int x,int y)
{
int ans = (-1)*0xfffffff;
if(u[x][y])
return dp[x][y];
if(x<n)
ans = max(ans,dfs(x+1,y));
if(y<m)
ans = max(ans,dfs(x,y+1));
for(int k=2; k<=m; k++)
if(y*k<=m)
ans = max(ans,dfs(x,y*k));
dp[x][y] = a[x][y] + ans;
u[x][y] = 1;
return dp[x][y];
}
int main()
{
int C;
cin>>C;
for(int i=0; i<C; i++)
{
cin >>n>>m;
memset(u,0,sizeof(u));
for(int j=1; j<=n; j++)
for(int k=1; k<=m; k++)
cin>>a[j][k];
dp[n][m] = a[n][m];
u[n][m] = 1;
cout<<dfs(1,1)<<endl;
}
return 0;
}
max sum
#include
using namespace std;
int main()
{
long long int n,t,i,q,k,st,en,summax,sum,a[100002];
scanf("%lld",&t);
for(q=1; q<=t; q++)
{
k=1,st=0,en=0,summax=-1000,sum=0;
scanf("%lld",&n);
for(i=1; i<=n; i++)
scanf("%lld",&a[i]);
for(i=1; i<=n; i++)
{
sum+=a[i];
if(sum>summax)
{
summax=sum;
st=k;
en=i;
}
if(sum<0)
{
sum=0;
k=i+1;
}
}
printf("Case %lld:\n%lld %lld %lld\n",q,summax,st,en);
if(q!=t)
printf("\n");
}
return 0;
}
最长上升子序列
#include
using namespace std;
int data[1000];
int dp[1000];
int main()
{
int n,max;
while(cin>>n)
{
for(int i=0; i<n; i++)
cin>>data[i];
dp[0]=1;
for(int i=1; i<n; i++)
{
max=0;
for(int j=0; j<i; j++)
{
if (data[j]<data[i])
{
if (max<dp[j])
max=dp[j];
}
}
dp[i]=max+1;
}
max=0;
for(int i=0; i<n; i++)
if (max<dp[i])
max=dp[i];
cout<<max<<endl;
}
return 0;
}
来来的正方形
#include
using namespace std;
#define MAX 500
int matrix[MAX][MAX];
int min(int a, int b)
{
return a < b ? a : b;
}
int main()
{
int m, n;
while(~scanf("%d%d", &m,&n))
{int max = 1;
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++)
scanf("%d", &matrix[i][j]);
for(int i = 1; i < m; i++)
for(int j = 1; j < n; j++)
if(matrix[i][j] == 1)
{
int mmin = min(matrix[i - 1][j], matrix[i][j - 1]);
mmin = min(matrix[i - 1][j - 1], mmin);
matrix[i][j] = mmin + 1;
if(max < matrix[i][j])
max = matrix[i][j];
}
printf("%d\n", max);
}
return 0;
}
中国象棋
#include
#include //用scanf(),printf()输入输出加快速度
#include //cstring内有memset()函数
using namespace std;
int a[9]= {0,-1,-1,-2,-2,1,1,2,2}; //数组a[]存储马控制的横坐标范围
int b[9]= {0,2,-2,1,-1,2,-2,1,-1}; //数组b[]存储马控制的纵坐标范围,注意相同下标的a,b之间有一定的对应关系,即除了(0,0)外|a|与|b|一个为1,另一个为2
int n,m,x,y,i,j;
int map[21][21]; //map[i][j]表示地图上(i,j)这个点是否是马的控制点
long long tripnum[21][21]; //tripnum[i][j]表示从(0,0)到(i,j)卒合法的行走路线总数
int main()
{
while(~scanf("%d%d%d%d",&n,&m,&x,&y))
{
memset(tripnum,0,sizeof(tripnum));
for(i=0; i<=20; i++)
for(j=0; j<=20; j++)
map[i][j]=1; //map[i][j]为1时表示(i,j)非控制点
for(i=0; i<=8; i++)
if(x+a[i]<=20 && x+a[i]>=0 && y+b[i]<=20 && y+b[i]>=0) //如果控制点在地图范围内,即这个点存在
map[x+a[i]][y+b[i]]=0; //将其设为0,表示这里被马控制
for(j=0; j<=20; j++) //从左到右遍历最上面一行的所有点
if(map[0][j]==1) //如果这个点不是控制点
tripnum[0][j]=1; //那么从(0,0)到达这个点的路线自然只有一条
else //否则这点不可到达,路线数为初值0条
break; //并且其右的点也不可达,不必继续遍历
for(i=0; i<=20; i++) //从上到下遍历最左边一列的所有点
if(map[i][0]==1) //如果这个点不是控制点
tripnum[i][0]=1; //那么从(0,0)到达这个点的路线自然只有一条
else //否则这点不可到达,路线数为初值0条
break; //并且其下的点也不可达,不必继续遍历
for(i=1; i<=n; i++) //从(1,1)这个点开始,逐行的去看(也可以逐列)
for(j=1; j<=m; j++)
if(map[i][j]==1) //如果这个点不是控制点
tripnum[i][j]=tripnum[i-1][j]*map[i-1][j]+tripnum[i][j-1]*map[i][j-1]; //那么到达它的路线数等于其左的点路线与其上的点之和,由于其左与其上的点有可能是控制点,所以要乘以控制系数map[i][j](这也是为什么用0代表控制,而用1代表非控制,而不是调换过来的原因)
printf("%lld\n",tripnum[n][m]);
}
return 0;
}