某农业学校 算法设计与分析-实验3

1.最短下降路径问题

【问题描述】

给定一个方形整数数组 A,我们想要得到通过 A 的下降路径的最小和。

下降路径可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列。
【输入形式】

第一行输入数组的大小n,第二行以后输入的n行分别是数组的第n行元素

【输出形式】

输出1行中含有一个数字,表示最短下降路径和。

【样例输入】

3

2 1 3

6 5 4

7 8 9
【样例输出】

13

#include<bits/stdc++.h>
using namespace std;
int a[1010][1010],dp[1010][1010];

int main()
{
	//方形矩阵的输入 
	char ch;
	int n=1;
	cin>>a[1][n];
	while((ch=getchar())!='\n')
		cin>>a[1][++n];
	for(int i=2;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>a[i][j]; 
		}
	}

	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(j==1)
			{
				dp[i][j]=min(dp[i-1][j],dp[i-1][j+1])+a[i][j];
			}
			else if(j==n-1)
			{
				dp[i][j]=min(dp[i-1][j-1],dp[i-1][j])+a[i][j];
			}
			else
			{
				dp[i][j]=min(min(dp[i-1][j-1],dp[i-1][j]),dp[i-1][j+1])+a[i][j];
			}
		}
	}
	int min=1e8+10;
	for(int i=1;i<=n;i++)
	{
		if(min>dp[n][i] && dp[n][i]!=a[n][i])
			min=dp[n][i];
	}
	cout << min;
	return 0;
}

2.最少硬币问题----动态规划

问题描述:

  设有n 种不同面值的硬币,各硬币的面值存于数组T[1:n ]中。现要用这些面值的硬币来找钱。可以使用的各种面值的硬币个数存于数组Coins[1:n ]中。对任意钱数0≤m≤20001,设计一个用最少硬币找钱m 的方法。

编程任务:

  对于给定的1≤n≤10,硬币面值数组T 和可以使用的各种面值的硬币个数数组Coins, 以及钱数m,0≤m≤20001,编程计算找钱m 的最少硬币数。

数据输入:

  由文件input.txt 提供输入数据,文件的第一行中只有1 个整数给出n 的值,第2 行起每行2 个数,分别是T[j] 和Coins[j] 。最后1 行是要找的钱数m。

结果输出:

  程序运行结束时,将计算出的最少硬币数输出到文件output.txt 中。问题无解时输出-1。

输入文件示例输出文件示例

input.txt              output.txt

3                          5

1 3

2 3

5 3

18

#include<bits/stdc++.h>
using namespace std;
int n,t[20],c[20],m;
int dp[1010];
/*
3
1 3
2 3
5 3
18
*/

int main()
{
	cin>>n;
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		cin>>t[i]>>c[i];
		sum+=t[i]*c[i];
	}
	cin>>m;
	if(sum<m)
	{
		cout << "-1";
		return 0;
	}
	
	for(int j=1;j<=m;j++)
	{
		dp[j]=1e8+10;
	}

	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=c[i];j++)
		{
			for(int k=m;k>=t[i];k--)
			{
				dp[k]=min(dp[k],dp[k-t[i]]+1);
			}
		}
	} 
	if(dp[m]!=1e8+10)
	{
		cout << dp[m];
	}
	else
	{
		cout << "-1";
	}
	return 0;
} 

3.独立任务最优调度问题----动态规划

问题描述

    用2 台处理机A 和B 处理n 个作业。设第i 个作业交给机器A 处理时需要时间ai ,若由机器B 来处理,则需要时间bi。由于各作业的特点和机器的性能关系,很可能对于某些i, 有ai ≥ bi ,而对于某些j,j≠i,有aj < bj 。既不能将一个作业分开由2 台机器处理,也没有一台机器能同时处理2 个作业。设计一个动态规划算法,使得这2 台机器处理完这n 个作业的时间最短(从任何一台机器开工到最后一台机器停工的总时间)。研究一个实例:(a1,a2,a3,a4,a5,a6)=(2,5,7,10,5,2);(b1,b2,b3,b4,b5,b6)=(3,8,4,11,3,4) 。

编程任务:

    对于给定的2 台处理机A 和B 处理n 个作业,找出一个最优调度方案,使2 台机器处理完这n 个作业的时间最短。

数据输入:

    由文件input.txt 提供输入数据。文件的第1 行是1 个正整数n, 表示要处理n 个作业。接下来的2 行中,每行有n 个正整数,分别表示处理机A 和B 处理第i 个作业需要的处理时间。

结果输出:

  程序运行结束时,将计算出的最短处理时间输出到文件output.txt 中。

输入文件示例输出文件示例

input.txt                       output.txt

6                                  15

2 5 7 10 5 2

3 8 4 11 3 4

#include<bits/stdc++.h>
using namespace std;
/*
6
2 5 7 10 5 2
3 8 4 11 3 4
*/
int n,a[1010],b[1010],tim[1010],s,minn=1e8;
int dp[1010][1010];

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		s+=a[i]; 
	}
	for(int i=1;i<=n;i++)
	{
		cin>>b[i];
	}
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		sum+=a[i];
		tim[i]=1e8+10;
		for(int j=0;j<=sum;j++)
		{
			if(j<a[i])
			{
				dp[i][j]=dp[i-1][j]+b[i];
			}
			else
			{
				dp[i][j]=min(dp[i-1][j]+b[i],dp[i-1][j-a[i]]);
			}
			tim[j]=min(tim[i],max(j,dp[i][j]));
		}
	}
	for(int i=1;i<=s;i++)
	{
		if(minn>tim[i])
		{
			minn=tim[i];
		}
	}
	cout << minn;
	return 0;
}

4.双调旅行售货员问题----动态规划

欧氏旅行售货员问题是对给定的平面上n 个点确定一条连接这n 个点的长度最短的哈密顿回路。由于欧氏距离满足三角不等式,所以欧氏旅行售货员问题是一个特殊的具有三角不等式性质的旅行售货员问题。它仍是一个NP 完全问题。最短双调TSP 回路是欧氏旅行售货员问题的特殊情况。平面上n 个点的双调TSP 回路是从最左点开始,严格地由左至右直到最右点,然后严格地由右至左直至最左点,且连接每一个点恰好一次的一条闭合回路。

编程任务:

  给定平面上n 个点,编程计算这n 个点的最短双调TSP 回路。

数据输入:

  由文件input.txt 给出输入数据。第1 行有1 个正整数n,表示给定的平面上的点数。接下来的n 行中,每行2 个实数,分别表示点的x 坐标和y 坐标。

结果输出:

  将计算的最短双调TSP 回路的长度(保留2 位小数)输出到文件output.txt 。

输入文件示例               输出文件示例

input.txt                  output.txt

7                            25.58

0 6

1 0

2 3

5 4

6 1

7 5

8 2

#include<bits/stdc++.h>
using namespace std;
/*
7
0 6
1 0
2 3
5 4
6 1
7 5
8 2
*/
const int INf=1e8+10;
int n;
double b[1010][1010];
struct pd
{
	int x,y;
}p[1010];

double dist(int i,int j)
{
	double sum=0;
	sum=(p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y);
	return sqrt(sum);
}

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>p[i].x>>p[i].y;
	}
	b[1][2]=dist(1,2);
	for(int i=3;i<=n;i++)
	{
		for(int j=1;j<=i-2;j++)
		{
			b[j][i]=b[j][i-1]+dist(i-1,i);
		}
		b[i-1][i]=INf;
		for(int k=1;k<=i-2;k++)
		{
			double temp=b[k][i-1]+dist(k,i);
			if(temp<b[i-1][i])
			{
				b[i-1][i]=temp;
			}
		}
	}
	b[n][n]=b[n-1][n]+dist(n-1,n);
	printf("%.2f",b[n][n]);
	return 0;
}

5.汽车加油行驶问题---动态规划

给定一个N*N 的方形网格,设其左上角为起点◎,坐标为(1,1),X 轴向右为正,Y 轴向下为正,每个方格边长为1。一辆汽车从起点◎出发驶向右下角终点▲,其坐标为(N, N)。在若干个网格交叉点处,设置了油库,可供汽车在行驶途中加油。汽车在行驶过程中应遵守如下规则:

(1)汽车只能沿网格边行驶,装满油后能行驶K 条网格边。出发时汽车已装满油,在

起点与终点处不设油库。

(2)当汽车行驶经过一条网格边时,若其X 坐标或Y 坐标减小,则应付费用B,否则

免付费用。

(3)汽车在行驶过程中遇油库则应加满油并付加油费用A。

(4)在需要时可在网格点处增设油库,并付增设油库费用C(不含加油费用A)。

(5)(1)~(4) 中的各数N、K、A、B、C 均为正整数。

编程任务:

  求汽车从起点出发到达终点的一条所付费用最少的行驶路线。

数据输入:

  由文件input.txt 提供输入数据。文件的第一行是N,K,A,B,C 的值,2 ≤ N ≤ 100,

2 ≤ K ≤ 10。第二行起是一个N*N 的0-1 方阵,每行N 个值,至N+1 行结束。方阵的第i 行第j 列处的值为1 表示在网格交叉点(i,j)处设置了一个油库,为0 时表示未设油库。各行相邻的2 个数以空格分隔。

结果输出: 程序运行结束时,将找到的最优行驶路线所需的费用,即最小费用输出到文件output.txt 中。文件的第1 行中的数是最小费用值。

输入文件示例                       输出文件示例

input.txt                          output.txt

9 3 2 3 6                              12

0 0 0 0 1 0 0 0 0

0 0 0 1 0 1 1 0 0

1 0 1 0 0 0 0 1 0

0 0 0 0 0 1 0 0 1

1 0 0 1 0 0 1 0 0

0 1 0 0 0 0 0 1 0

0 0 0 0 1 0 0 0 1

1 0 0 1 0 0 0 1 0

0 1 0 0 0 0 0 0 0

#include<bits/stdc++.h>
using namespace std;
/*
9 3 2 3 6
0 0 0 0 1 0 0 0 0
0 0 0 1 0 1 1 0 0
1 0 1 0 0 0 0 1 0
0 0 0 0 0 1 0 0 1
1 0 0 1 0 0 1 0 0
0 1 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0 1
1 0 0 1 0 0 0 1 0
0 1 0 0 0 0 0 0 0
*/
const int INf=1e8+10;
int N,K,A,B,C;
int a[1010][1010];
int f[1010][1010][4];//4:0表示最少费用,1表示行驶的网格工具 
int d[4][3]={{-1,0,0},{0,-1,0},{1,0,B},{0,1,B}};

int main()
{
	cin>>N>>K>>A>>B>>C;
	for(int i=1;i<=N;i++)
	{
		for(int j=1;j<=N;j++)
		{
			cin>>a[i][j];
		}
	}
	for(int i=1;i<=N;i++)
	{
		for(int j=1;j<=N;j++)
		{
			f[i][j][0]=INf;
			f[i][j][1]=K;
		}
	}
	f[1][1][0]=0;f[1][1][1]=K;
	
	
	for(int i=1;i<=N;i++)
	{
		for(int j=1;j<=N;j++)
		{
			if(i==1 && j==1) continue;
			int minm=INf,mins;
			int maxm,maxs;
			
			for(int k=0;k<=3;k++)
			{
				if(i+d[k][0]<1||i+d[k][0]>N||j+d[k][1]<1||j+d[k][1]>N)
					continue;
				maxm=f[i+d[k][0]][j+d[k][1]][0]+d[k][2];
				maxs=f[i+d[k][0]][j+d[k][1]][1]-1;
				if(a[i][j]==1) 
				{
					maxm+=A;
					maxs+=K;
				}
				if(a[i][j]==0 && maxs==0 &&(i!=N || j!=N))
				{
					maxm+=A+C;
					maxs=K;
				}
				if(minm>maxm)
				{
					minm=maxm;
					mins=maxs;
				}
			}
			
			if(f[i][j][0]>minm)
			{
				f[i][j][0]=minm;
				f[i][j][1]=mins;
			}
		}
	}
	int maxx=0,anss=0;
	for(int i=1;i<=N;++i)
	{	
		for(int j=1;j<=N;++j)
		{
			if(f[i][j][1]>maxx)
			{
				maxx=f[i][j][1];
				anss=f[i][j][0];
			}
		}	
	} 
	cout << anss;
	return 0;
}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值