动态规划实验解析

一、互不攻击的士兵

你有一个含n个格子的一维棋盘。你可以往棋盘上放任意多个士兵。(每个格子只能放置一个士兵)。一个士兵会攻击与他相邻的左右两个格子中的士兵。现在问你,有多少种放置的方案使得棋盘上的士兵互不攻击?

题目要求1

我们以0代表格子里无士兵,1代表格子里有士兵。 一个格子两种状态0,1,两个格子00、01、10,三个格子000、001、010、100、101,四个格子0000、0001、0010、0100、1000、1001、1010当然要做这个题目很简单,直接找规律就可以了,但是因为是要写实验报告的、还是按照实验流程来吧
嗯?三个格子0|00,0|01,0|10,10|0,10|1
四个格子0|000,0|001,0|010,0|100,0|101,10|00,10|01,10|10

  • 划分状态(划分子问题):对于本题来说,可以认为n个格子的最优解由0和n-1个格子的以及10和n-2个格子状态组成
  • 状态表示:我们用f(n)表示n个格子的放置方案
  • 状态转移方程:f(n)=f(n-1)+f(n-2)
  • 确定边界:最小的问题就是1个格子和2个格子,而且不可再分,所以边界值n=1 and n=2

既然已经确定了状态转移方程和边界值,接下来直接解题便是.

#include<iostream>
using namespace std;
int f(int n){
	if(n==1) return 2;
  	else if(n==2) return 3;
  	else return f(n-1)+f(n-2);
}
int main(){
  	int n;
  	cin>>n;
  	cout<<f(n);
	return 0;
}

上面就是原生态的代码,当然考虑到效率问题和优化问题,我们使用一维数组f[n]模拟棋盘,会更快一些,而且储存了每个状态的最优解.

#include<iostream>
using namespace std;
int f[50]={2,3};
int main(){
	for(int i=2;i<50;i++){
		f[i]=f[i-1]+f[i-2];
	}
  	int n;
  	cin>>n;
  	cout<<f[n-1];
	return 0;
}

效果很明显,优化前

优化后:

二、爬楼梯

有一天,两人比赛从第1层开始,看谁能更快到达第m层,A一层一层往下走,这显然太慢了,为了公平起见,于是B给出了多个单向快捷通道,可以只使用1s就能从第u层到达第v层。已知到相邻的层需要1s,可以前进到下一层也可以回退到上一层,只能在【1,m】层之间转移,即不能到0或m+1层等层数。请你帮助A计算出到达第m层所需要的最少时间,战胜B (原题不正经,稍微改了一下)。

这题有点像图的最短路径,特殊的是每个边的权值都是1。官方提示说用Floyd算法,然而我根本不记得,直接bfs解决。但是实验要求动态规划,我还是写一下吧。Floyd算法看下面的链接。

Floyd解法

Floyd算法详解

  • 简单来说对Floyd算法,首先建立邻接矩阵dp[n][n],对Floyd算法来说,状态转移方程为d[i][j]=min{d[i][j],d[i][k]+d[k][j]}
    算法如下
#include<iostream>
#define INF 1000
using namespace std;

int dp[202][202]={0};

int main(){
    //初始化
  	int n,m;
  	cin>>n>>m;
  	for(int i=0;i<201;i++){
  	    for(int j=0;j<201;j++){
            if(i+1==j||i-1==j)
                dp[i][j]=1;
            else
                dp[i][j]=INF;
  	    }
  	}
  	int i,j;
  	while(n--){
        cin>>i>>j;
        dp[i][j]=1;
  	}
  	//算法
  	for(int k=1;k<=m;k++)
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++)
                if(dp[i][j]>dp[i][k]+dp[k][j])
                    dp[i][j]=dp[i][k]+dp[k][j];

    cout<<dp[1][m];
	return 0;
}

Floyd的时间复杂度是 O ( n 3 ) O(n^3) ,换成广度优先bfs的话,时间复杂度为 O ( n ) O(n)

BFS(广度优先)

算法思想是 首先入队第一个顶点,遍历队首所有能抵达的地方,将其入队,之后队首出队,继续上述操作直至队列为空(所有顶点已走完),因为该题目的特殊性,所有路径长度唯一。

算法如下

// 构建邻接矩阵
#include<iostream>
#define INF 1000
using namespace std;

int visit[202];
int a[202][202]={0};
void print(int m){
 for(int i=1;i<=m;i++){
        cout<<visit[i]<<" ";
    }cout<<endl;
}
int queue[1000];
int main(){
  	int n,m;
  	cin>>n>>m;
  	for(int i=0;i<201;i++){
        a[i][i+1]=a[i+1][i]=1;
        visit[i]=INF;
  	}
  	int i,j;
  	while(n--){
        cin>>i>>j;
        a[i][j]=1;
  	}

  	visit[1]=0;
  	int f=0,e=0;
    queue[e++]=1;
  	while(f<e){
        int x=queue[f];
        int y=visit[x];
        for(i=1;i<=m;i++){
            if(a[x][i]!=0){
                if(visit[i]>y+1){
                    visit[i]=y+1;
                    queue[e++]=i;
                }
            }
        }
        f++;
  	}
    cout<<visit[m];
	return 0;
}

显然比Floyd快一些。

发布了3 篇原创文章 · 获赞 1 · 访问量 62

猜你喜欢

转载自blog.csdn.net/weixin_43323747/article/details/105542230