NEFU19级算法设计与分析课程设计

欢迎指正!!!谢谢大噶!!!

算法课设(持续更新ing)

分治策略

输油管道问题
【题目描述】
某石油公司计划建造一条由西向东的主输油管道,该管道要穿过一个有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 <algorithm>
using namespace std;
int Partition(int a[],int left,int right)   
{
    int key=a[left];     
    while(left<right)
    {
        while(left<right&&a[right]>=key)    //从最右边寻找,当找到比key小的值时退出循环
            right--;
        if(left<right)
            a[left]=a[right];
        while(left<right&&a[left]<=key)    //从最左边开始寻找,当找到比key大的值退出循环
            left++;
        if(left<right)
            a[right]=a[left];
    }
    a[left]=key;
    return left;
}
void Quicksort(int a[],int left,int right)   //快速排序 
{
    if(left<right)
    {
        int q=Partition(a,left,right);
        Quicksort(a,left,q-1);
        Quicksort(a,q+1,right);
    }
}
int main()
{
   int n, bestd = 0, Y;      //n为管道长度,bestd为各油井到主管道之间的输油管长度最小总和,Y为主管道位置 
   cin >> n;
   int x[n], y[n]; 
   for (int i = 0; i < n; i++)
      cin >> x[i] >> y[i];
   Quicksort(y, 0, n - 1);
   if (n % 2==0)        //n为偶数,这里的Y不必特地求出准确的小数值,由于在主管道的南北方有相同数量的油井,主管道只需要在中间两个数之间即可,距离之和是不会变的。
      Y = (y[n/2-1]+y[n/2])/2;
   else                 //n为奇数数
      Y = y[n / 2];
   for (int i = 0; i < n;i++)
      bestd += abs(y[i] - Y);
   cout << "主管道最优的位置应该为:直线y=" << Y << endl;
   cout << "各油井到主管道之间的输油管长度最小总和为:" << bestd << endl;
   return 0;
}


动态规划

4、台阶问题
问题描述:有n级台阶,一个人每次上一级或者两级,问有多少种走完n级台阶的方法。

经典斐波那契数列。

#include <iostream>
using namespace std;
int climbStairs(int n) 
{
	int a[n+1];  //a[i]表示走到第i阶楼梯的方法数量 
    if(n==1)   
        return 1;
    if(n==2)
        return 2;
    a[1]=1;
    a[2]=2;
    for(int i=3;i<=n;i++)
        a[i]=a[i-1]+a[i-2];
    return a[n];
}
int main()
{
  int n;
  cin>>n;
  cout<<climbStairs(n)<<endl;
  return 0;
} 

实际情况:给定一个矩阵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>
using namespace std;
#define N 100
#define Dage 10000
int map[N+1][N+1]={0};
int dp[N+1][N+1]={0};
int flag[N + 1][N + 1]={0};
int main()
{
    int n,m;
    cin >> n >> m;
    for (int i = 1; i <= n;i++)
        for (int j = 1; j <= m;j++)
            cin >> map[i][j];
    for (int i = n; i >= 1; i--)
        for (int j = m; j >= 1;j--)
        {
            if(i==n)
            {
                dp[i][j] = dp[i][j+1] + map[i][j];//最后一行只能往右走
                flag[i][j] = 1;    //1表示向右走
            }
            else
            {
                if(j==m)       //最右边的点只能向下走
                {
                    dp[i][j]=dp[i+1][j]+map[i][j];
                    flag[i][j] = 0;    //0表示向下走
                }
                else
                {
                     if(dp[i+1][j]>dp[i][j+1])
                    {
                        dp[i][j] = dp[i][j + 1]+map[i][j];
                        flag[i][j] = 1;
                    }
                    else
                    {
                        dp[i][j] = dp[i + 1][j]+map[i][j];
                        flag[i][j] = 0;
                    }
                }
            }
        }
    cout << dp[1][1] << endl;
    int i = 1, j = 1, x = dp[i][j];
    while(i<=n&&j<=m)
    {
        cout << "(" << i << "," << j << ")";
        if(flag[i][j]==0)         //0表示向下走
            i = i + 1;
        else                     //1表示向右走
            j = j + 1;
    }
    return 0;
}
/*
测试数据:
4 4
1 1 1 1 
9 9 9 1
9 9 9 1
9 9 9 0

4 4
1 9 9 9
1 9 9 9
1 9 9 9
1 1 1 0

4 4
1 3 5 9
8 1 3 4
5 0 6 1
8 8 4 0
*/

贪心算法

文件连接问题:给定一个大小为n的数组F,数组元素F[i]表示第i个文件的长度。现在需要将所有文件合并成一个文件,文件越长后面连接成新文件花费的时间越长,试给出贪心算法给出文件连接顺序,保证连接文件花费的时间最短。

这题应该就是哈夫曼树的思想吧。

#include <iostream>
#include <algorithm>
using namespace std;
#define N 10086
int main()
{
   int n, F[100],sum=0;
   cin >> n;
   for (int i = 0; i < n;i++)
      scanf("%d", &F[i]);
   sort(F , F + n );
   for (int i = 0; i < n-1;i++)
   {
      sort(F + i, F + n);
      F[i + 1] = F[i] + F[i + 1];
      sum += F[i + 1];
   }
   cout <<"连接文件的最小花费为:" <<sum << endl;
   system("pause");
   return 0;
}
/*
数据测试:
5 
4 3 1 2 5
*/
回溯算法

在这里插入图片描述
排列树问题吧应该!

#include <iostream>
#include <math.h>
using namespace std;
#define N 100
int a[N+1];
int n;
int count=0;
bool SushuCheak(int t)
{
   int sum = a[t] + a[t - 1];
   int k = sqrt(sum);
   for (int i = 2; i <= k;i++)
   {
      if(sum%i==0)
         return false;
   }
   return true;
}
void Backtrack(int t)
{
   if(t>n)
   {
      int sum = a[n] + a[1];
      int k = sqrt(sum);
      int flag = 1;
      for (int i = 2; i <= k;i++)
      {
         if(sum%i==0)
         {
            flag = 0;
            break;
         }
      }
      if(flag==1)
      {
      	count++;
        for (int i = 1; i <= n; i++)
            cout << a[i] << " ";
        cout<<endl;
      }
   }
   else
   {
      for (int i = t; i <= n;i++)
      {
         swap(a[i], a[t]);
         if(SushuCheak(t))
            Backtrack(t + 1);
         swap(a[i], a[t]);
      }
   }
}
int main()
{
   cin >> n;
   for (int i = 1; i <= n;i++)
      a[i] = i;
   Backtrack(2);
   cout<<"总共有"<<count<<"种环"<<endl; 
   return 0;
}

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值