算法设计的两个例子

本文通过两个实例介绍算法设计,包括一个调度问题和一个投资问题。调度问题使用贪心算法,按照加工时间从小到大排序以最小化总完成时间;投资问题通过蛮力算法枚举所有可能的投资组合以最大化总效益。这两个问题展示了不同算法在解决实际问题中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法设计的两个例子

标签(空格分隔): 算法知识文档


例1:调度问题

问题:

有n项任务,每项任务加工时间已知.从0时刻开始陆续安排到一台机器上加工.每个任务的完成时间是从0时刻到任务加工截至的时间.

求:

总完成时间(所有任务完成时间之和)最短的安排方案.

实例:

任务集: S={1,2,3,4,5}S={1,2,3,4,5}
加工时间: t1=3,t2=8,t3=5,t4=10,t5=15t1=3,t2=8,t3=5,t4=10,t5=15

分析:

我们需要计算的是所有任务完成时间之和.因为只有一台机器,所以做第i项任务需等待第i-1项任务做完,我们所要求解的是如何安排做这些任务的顺序使得总时间最小.比如,如果按照实例所给出的5个任务顺序的进行加工,需要的总时间计算如下:

tsum=t1+(t1+t2)+(t1+t2+t3)+(t1+t2+t3+t4)+(t1+t2+t3+t4+t5)tsum=t1+(t1+t2)+(t1+t2+t3)+(t1+t2+t3+t4)+(t1+t2+t3+t4+t5)

求得: tsum=35+84+53+102+151=97tsum=3∗5+8∗4+5∗3+10∗2+15∗1=97

贪心算法的解:

算法描述: 优先选择加工时间短的任务先完成
算法: 按照加工时间从小到大排列(3,5,8,10,15)(3,5,8,10,15)
解: 任务加工顺序 (1,3,2,4,5)(1,3,2,4,5)

总完成时间: tsum=35+54+83+102+151=94tsum=3∗5+5∗4+8∗3+10∗2+15∗1=94
当前总时间是最小的,后面会给出证明.我们先进行问题的建模.

问题建模

输入:
任务集合: S={1,2,3,...,n}S={1,2,3,...,n}
第j项任务加工时间: tjZ+,j=1,2,3,..,ntj∈Z+,j=1,2,3,..,n

输出:
调度II (S的排列) i1,i2,i3,...,ini1,i2,i3,...,in

目标函数:
I的完成时间, Tsum(I)=nk=1(nk+1)tikTsum(I)=∑k=1n(n−k+1)∗tik

解:II∗使得目标函数的值达到最小

Tsum(I)=min{Tsum(I)|IS}Tsum(I∗)=min{Tsum(I)|I是S的排列}

证明贪心算法的正确性:

设计策略:
加工时间短任务的先做

算法:
根据加工时间从小到大排序,依次进行加工

算法的正确性:
对所有输入样例都得到最优解

证明:
加入调度ffi,j,j=i+1i,j,j=i+1 项任务逆序,即ti>tjti>tj
交换任务顺序j,i,j=i1j,i,j=i−1得到新的调度gg中有tj<titj<ti
带入目标函数公式不难知道:

A=B1A=B−1

Tsum(g)Tsum(f)=(Ati+Btj)(Atj+Bti)=tjti<0Tsum(g)−Tsum(f)=(A∗ti+B∗tj)−(A∗tj+B∗ti)=tj−ti<0

可知,减少一个逆序便能减少时间,将任务时间按从小到大排序得到II∗,当前序列中没有相邻的逆序对,Tsum(I)Tsum(I∗)就是最优解.

CODE:CODE:
/************************************************
@author: hejun
算法复杂度:O(NlogN)
简单的任务调度问题,还没有经过oj题目的验证
************************************************/
#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
#define MAX_N 100005 // 最大任务总数
int t[MAX_N]; // 第i项任务需要的时间
int n; // 有n项任务

 // 贪心算法解决
void solve(){
    LL ans = 0;
    sort(t, t+n); // 按照任务需要完成的时间从小到大排序
    for(int i = 0; i < n; i++) ans += (n-i)*t[i]; // 计算最优解
    printf("%lld\n", ans); // 输出最优解
}

int main(){
    freopen("in.txt", "r", stdin);
    int i;
    while(~scanf("%d", &n) && n){ // 输入有n项任务
        for(i = 0; i < n; i++) scanf("%d", &t[i]); // 输入第i项任务需要的时间
        solve(); // 贪心算法解决
    }
    return 0;
}

运行实例:
输入:
5
3 8 5 10 15
输出:
94

例2:投资问题

问题:

mm元钱,投资n个项目.效益函数fi(x)fi(x),表示第ii个项目投资x元的效益, i=1,2,3,...,n.i=1,2,3,...,n.求如何分配每个项目的钱使得总效益最大?

实例:

5万元,投资给4个项目,效益函数:

xx f1(x)f2(x)f2(x)f3(x)f3(x)f4(x)f4(x)
00000
1110220
21251021
313103022
414153223
515204024

问题建模:

输入:
n,m,fi(x),i=1,2,3,..,n,x=1,2,...,mn,m,fi(x),i=1,2,3,..,n,x=1,2,...,m

解:
nn维向量<x1,x2,...,xn>,xiii,使
目标函数:

maxi=1nfi(xi)max∑i=1nfi(xi)

约束条件:
i=1nxi=m,xiN∑i=1nxi=m,xi∈N

蛮力算法:

描述:
枚举所有可能的解<x1,x2,...,xn><x1,x2,...,xn>满足x1+x2+...+xn=mx1+x2+...+xn=m然后求解当前解的效益总值,得到最大的效益值对应的解向量.

实际计算:
对于当前实例:
x1+x2+x3+x4=5x1+x2+x3+x4=5
s1=<0,0,0,5>v(s1)=24s1=<0,0,0,5>v(s1)=24
s2=<0,0,1,4>v(s2)=25s2=<0,0,1,4>v(s2)=25
s3=<0,0,2,3>v(s3)=32s3=<0,0,2,3>v(s3)=32

s56=<5,0,0,0>v(s56)=15s56=<5,0,0,0>v(s56)=15

解:
s=<1,0,3,1>v(s)=11+0+30+20=61s=<1,0,3,1>v(s)=11+0+30+20=61

算法效率分析:
方程x1+x1+x_{2}+ … +xn=mxn=m的非负整数解<x1,x2,...,xn><x1,x2,...,xn>的个数估计:
可行解表示成0,1序列:m个1,n-1个0
1...101...101...11...101...101...1
n=4,m=7n=4,m=7
可行解<1,2,3,1><1,2,3,1>可以表示成序列:10110111011011011101
所以这样的序列个数就是在m+n1m1m+n−1个数字中选择m个1
序列个数是输入规模的指数函数:

Cmm+n1=(m+n1)!(n1)!m!=Ω((1+ϵ)m+n1)Cm+n−1m=(m+n−1)!(n−1)!m!=Ω((1+ϵ)m+n−1)

小结:

问题求解的关键:

  • 建模: 对输入参数和解给出形式化或者半形式化的描述
  • 设计算法:采用什么算法设计技术,正确性–是否对所有的实例都得到正确的解
  • 分析算法–效率
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值