NEFU大二下学期算法分析与设计课程设计内容,四大主要算法个选其一。
一、分治策略
1、输油管道问题
【题目描述】
某石油公司计划建造一条由西向东的主输油管道,该管道要穿过一个有n口油井的油田。从每口油田都要有一条输油管道沿最短路径(或南或北)与主管道相连。如果给定n口油井的位置,即它们的x坐标(东西向)和y坐标(南北向),应如何确定主管道的最优位置,即使各油井到主管道之间的输油管长度总和最小的位置?
【输入】
第一行是一个整数n,表示油井数量(1-1000之间),接下来n行是油井的位置,每行两个整数x和y。
【输出】
各油井到主管道之间的输油管道最小长度总和。
【输入样例】
5
1 2
2 2
1 3
3 -2
3 3
【输出样例】
6
解题思路
油管是自西向东的主管道,油井是分布在主管道周围,但计算油井到主管道距离时与横坐标无关,只需要油井纵坐标减去主管道所在的纵坐标的绝对值即可。
求油管的纵坐标就找中位数,找中位数用快速排序算法。
代码如下(示例):
#include <iostream>
#include <math.h>
using namespace std;
/*油管问题
【输入样例】第一行是一个整数n,表示油井数量(1-1000之间)
接下来n行是油井的位置,每行两个整数x和y。
5
1 2
2 2
1 3
3 -2
3 3
【输出样例】各油井到主管道之间的输油管道最小长度总和。
6
思路:油管是自西向东的主管道,油井是分布在主管道周围,
但计算油井到主管道距离时与横坐标无关,只需要油井纵坐标减去主管道所在的纵坐标的绝对值即可。
求油管的纵坐标就找中位数,找中位数用快速排序算法。
*/
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[(l + r)/2];
while (i < j)
{
do i ++ ; while (q[i] < x);
do j -- ; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
quick_sort(q, l, j), quick_sort(q, j + 1, r);
}
void min_road_sum(int a[],int n)
{
int mid=a[n>>1];
int sum=0;
for(int i=0;i<n;i++)
sum+=fabs(mid-a[i]);
printf("油管主干道长度为%d",sum);
}
int main()
{
int a[100];
int n;
printf("请输入n个油井的数目\n并依次输入位置\n");
scanf("%d",&n);
for(int i=0,x;i<n;i++)
scanf("%d %d",&x,a+i);
quick_sort(a,0,n-1);
min_road_sum(a,n);
return 0;
}
二、动态规划
1.台阶路径
给定一个矩阵m,从左上角开始每次只能向右走或者向下走,最后达到右下角的位置,路径中所有数字累加起来就是路径和,返回所有路径的最小路径和,如果给定的m如下,那么路径1,3,1,0,6,1,0就是最小路径和,返回12.
1 3 5 9
8 1 3 4
5 0 6 1
8 8 4 0
代码如下(示例):
#include <iostream>
#include<algorithm>
/*
4
1 3 5 9
8 1 3 4
5 0 6 1
8 8 4 0
*/
void put(int d[][100],int n)
{
for(int i=0;i<n;i++)
{for(int j=0;j<n;j++)
printf("%d ",d[i][j]);
printf("\n");
}
}
using namespace std;
int main()
{
int a[100][100],n;
int d[100][100],c[100];
scanf("%d",&n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&a[i][j]);
d[0][0]=a[0][0];
for(int i=1;i<n;i++)
{d[0][i]=a[0][i]+d[0][i-1];d[i][0]=a[i][0]+d[i-1][0];}
for(int i=1;i<n;i++)
for(int j=1;j<n;j++)
d[i][j]=a[i][j]+(d[i-1][j]>d[i][j-1]?d[i][j-1]:d[i-1][j]);
// printf("矩阵如下:\n");
// put(a,n);
printf(" 最短路径长度是%d\n 路径是:\n开始:%d->",d[3][3],a[0][0]);
for(int i=0,j=0;i<n-1;i++)
{
if(d[i][j]==d[n-1][n-1])break;
if(d[i][j+1]<d[i+1][j])
{
printf("%d->",a[i][j+1]);j++;i--;
}
else{
printf("%d->",a[i+1][j]);
}
}
printf("%d->结束",a[n-1][n-1]);
return 0;
}
2.动态规划方程
动态规划方程是:d[i][j]=a[i][j]+min(d[i-1][j],d[i][j-1]);
三、贪心策略
站台安排
一个火车站有一个所有火车到达和离开的时间表,需要找出最小站台数,使得按照此时间表调度时,可以容纳所有的火车。已知火车时刻表如下所示,试编程实现,需要的最少站台有几个。
火车 到达时间 离开时间 火车 到达时间 离开时间
车次A 0900 0930 车次C 1030 1100
车次B 0915 1300 车次D 1045 1145
代码如下:
#include <iostream>
/*
测试数据
第一组
4
0900 0930
0915 1300
1030 1100
1045 1145
第二组
6
8 11
1 4
5 7
3 5
6 10
0 6
*/
using namespace std;
void sort(int a[][100],int n)
{
for(int i=0;i<n-1;i++)
for(int j=0;j<n-i-1;j++)
{
if(a[j][1]>a[j+1][1])
{
int t=a[j][1],m=a[j][0];
a[j][1]=a[j+1][1];a[j][0]=a[j+1][0];
a[j+1][1]=t;a[j+1][0]=m;
}
}
}
void GreedySelector(int n,int s[][100],int a[],int x,int k)
{
a[k]=x;
int j=k;
for(int i=k+1;i<n;i++)
{
if(s[i][0]>s[j][1])
{
a[i]=x;j=i;
}
}
}
int main()
{
int s[100][100];
int n,i,a[100];
//a数组是标记数组,标记第i+1列车是否被安排站台
printf("第一行请输入列车到达总数n\n第二行起依次输入每列列车的到达时间和离站时间\n");
scanf("%d",&n);
for(i=0;i<n;i++)
{scanf("%d %d",&s[i][0],&s[i][1]);
a[i]=0;
}
sort(s,n);//按照离站时间排序
int x=1;//为火车安排第x个站台
for(i=0;i<n;i++)
{
if(a[i]!=0)continue;
GreedySelector(n,s,a,x,i);
x++;
}
int m=-1;
for(i=0;i<n;i++)
if(a[i]>m)m=a[i];
printf(" 需要安排%d个站台\n",m);
for(i=0;i<n;i++)
printf("第%d列火车安排在第%d个站台\n",i+1,a[i]);
return 0;
}
四、回溯
素数环
(1)问题描述:输入正整数n,把整数1,2,3,4……n组成一个环,使得相邻的两个整数之和均为素数。
(2)样例
输入:
6
输出:
1 4 3 2 5 6
1 6 5 2 3 4
(3)n=4时的搜索解空间树。
代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
int a[100],n,is_use[100];
int is_prime(int x)
{
for(int i=2;i<x;i++)
if(x%i==0)return 0;
return true;
}
void dfs(int t)
{
if(t==n&&is_prime(a[t-1]+a[0]))
//判断最后一个数与首位数的和是否为素数
{
cout<< " 素数环是" << endl;
for(int i=0;i<n;i++)
cout<< a[i] << " ";
printf("\n\n");
}
else
{
for(int i=2;i<=n;i++)
{
if(is_prime(i+a[t-1])&&!is_use[i])
//判断选入的数是否与前一个数之和为素数,并且重复选入
{
a[t]=i;
is_use[i]=1;
dfs(t+1);
a[t]=0;
is_use[i]=0;
}
}
}
}
int main()
{
cout<<" 请输入素数环的范围n:"<<endl;
cin>>n;
for(int i=2;i<n;i++)
is_use[i]=0;
a[0]=1;//首位为1,因为是环,哪个数在第一个都一样,默认首位是1
dfs(1);
return 0;
}
总结
算法课程自己学的不好,这学期补课忙到爆炸,时间和精力花在算法上极少,很是难过。幸亏我们学校的课程设计不难,都能讨论找资料完成,也就浑水摸鱼混过去了。一定要好好学习算法!