常见算法问题解决

  • 二分查找
#include<cstdio>
#include<iostream>
#include<bits/stdc++.h>
#define N 1001
using  namespace std;
int Num = 0;
double ans;
int binarySearch( const int b[], int searchKey, int low, int high ) {
        int middle;

        while( low <= high ) {
              middle = ( low + high ) / 2;
              if (searchKey == b[middle]) {
                  Num++;
                  return middle;
              }
              else if ( searchKey < b[middle] ) {
                  high = middle - 1;
                  Num++;
              }
              else {
                  low = middle + 1;
                  Num++;
              }
        }
        return -1; // not found
    }

int main()
{
    int arr[N];
    cout << "元素的个数" << setw(18) << "理论平均查找次数" << setw(22) << "实际平均查找次数" << endl;
    for ( int j=100; j <=1000; j+=100 )
    {
        Num = 0;
        arr[0]=10+rand()%15;
        for(int i=1; i<j; i++) {
              // 生成递增随机数列
              arr[i]=arr[i-1]+1+rand()%3+rand()%10;
        }
        int SearchTimes = 10;
        for (int time=0; time < SearchTimes; time++)
        {
            int index = rand() % j;	//  suffix 为要搜索的元素下标
            int key = arr[index];	//    key 为要查找的数据
            int result = binarySearch(arr, key, 0, j-1 );
        }
        ans = (double)(Num) / SearchTimes;
        cout << setw(6) << j << setw(18) << int( log(j)/log(2) )+0.5<< setw(22) <<ans << endl;

    }
    return 0;
}

  • 0-1背包问题的动态规划
#include<bits/stdc++.h>
#define N 101
using namespace std;
int n,w[N],v[N],W;//n个物品,重量存在w数组,价值存在v数组,背包容量为W
int c[N][N] = {0},x[N];//c[i][j]表示前i个物品放在容量为j的背包获得的最大价值,x[i]表示第i个物品是否放入背包
void compute()
{
    int i,j;
    for(i = 1;i <= n;i++)
        for(j = 1;j<= W;j++)
        {
            if(j < w[i])//物品重量大于背包容量则不放
                c[i][j] = c[i-1][j];
            else //能放,则判断放还是不放能使价值最大化
                c[i][j] = max(c[i-1][j],c[i-1][j-w[i]]+v[i]);
        }
    j = W;//回退判断哪些物品放进去了
    for(i = n;i > 0;i--)
    {
        if(c[i][j] >c[i-1][j])
        {
            x[i] = 1;
            j -= w[i];
        }
        else
            x[i] = 0;
    }
    cout << "放入背包的有:"<<endl;
    for(i = 1;i <= n;i++)
        if(x[i])
            cout <<i<<" ";
    cout << endl;
}
int main()
{
    cout <<"请输入物品数和背包容量:"<<endl;
    cin >> n >> W;
    cout <<"请依次输入每个物品的重量和价值:"<<endl;
    for(int i = 1;i <= n;i++)
        cin >> w[i] >> v[i];
    compute();
    return 0;
}
/*测试数据
5 10
2 6 5 3 4 5 2 4 3 6
*/


  • 棋盘覆盖的分治解法
#include <iostream>
#define N 1024
using namespace std;

int BOARD_SZ;
static int tile = 1;
static int board[N][N] = {0};
void chess_board(int tr, int tc, int dr, int dc, int size)
{
    if(size == 1)
        return;

    int t = tile++;
    int sz = size / 2;    //每次进行划分

    if(dr < tr+sz && dc < tc+sz)  //注意一共四种情况,<>=这几个符号要控制好边界
        chess_board(tr, tc, dr, dc, sz);
    else{
        board[tr+sz-1][tc+sz-1] = t;
        chess_board(tr, tc, tr+sz-1, tc+sz-1, sz);
    }


    if(dr < tr+sz && dc >= tc+sz)   //notice < >=
        chess_board(tr, tc+sz, dr, dc, sz);
    else{
        board[tr+sz-1][tc+sz] = t;
        chess_board(tr, tc+sz, tr+sz-1, tc+sz, sz);
    }


    if(dr >= tr+sz && dc < tc+sz)   //notice >= <
        chess_board(tr+sz, tc, dr, dc, sz);
    else{
        board[tr+sz][tc+sz-1] = t;
        chess_board(tr+sz, tc, tr+sz, tc+sz-1, sz);
    }


    if(dr >= tr+sz && dc >= tc+sz)  //notice >= >=
        chess_board(tr+sz, tc+sz, dr, dc, sz);
    else{
        board[tr+sz][tc+sz] = t;                       //标记一个假设的特殊点
        chess_board(tr+sz, tc+sz, tr+sz, tc+sz, sz);   //递归该部分
    }
}

void print_chess_board()
{
    cout.setf(ios::left);     //左对齐
    for(int i=0; i<BOARD_SZ; ++i){
        for(int j=0; j<BOARD_SZ; ++j){
            cout.width(3);    //打印宽度为3
            cout<<board[i][j];
        }
        cout<<endl;
    }
}

int main()
{
    int dr,dc;
    cout << "请输入特殊方格的行列号和规格:"<<endl;
    cin >> dr >> dc >> BOARD_SZ;
    chess_board(0, 0, dr, dc, BOARD_SZ);
    print_chess_board();
    return 0;
}


  • 独立任务的最优调度问题
//F[k,x]表示处理完第k个作业且A机器到达了时间x,B机器到达的最小时间,
//处理完第i个作业,如果是A处理的那么F[i,x+a[i]] = b[i-1]
//否则F[i,x] =f[i-1,x]+ b[i]
#include<bits/stdc++.h>
#define N 1001
using namespace std;
int n,a[N] = {0},b[N] = {0},F[N][N] = {0},sumA = 0;//n个作业
void init()
{
    cout << "请输入作业的个数: ";
    cin >> n;
    cout <<"请输入作业在机器A上的时间:"<<endl;
    for(int i = 1;i <= n;i++)
    {
         cin >> a[i];
         sumA += a[i];
    }
    cout <<"请输入作业在机器B上的时间:"<<endl;
    for(int i = 1;i <= n;i++)
        cin >> b[i];
}
void solve()
{
    for(int i = 1;i <= n;i++)
    {
        for(int j = 0;j <= sumA;j++)
        {
            if(j >= a[i])
                F[i][j] = min(F[i-1][j-a[i]],F[i-1][j]+b[i]);
            else
                F[i][j] = F[i-1][j] + b[i];
        }
    }
}
void print()
{
    int temp = 0,minv = 99999;
    for(int j = 0;j <= sumA;j++)//
    {
        temp = max(F[n][j],j);
        if(minv > temp)
            minv = temp;
    }
    cout<<"最小完成时间为:"<<endl;
    cout << minv;
}
int main()
{
    init();
    solve();
    print();
    return 0;
}
/*
6
2 5 7 10 5 2
3 8 4 11 3 4
*/

  • 哈夫曼编码
#include <iostream>
#include <queue>
using namespace std;
int bit[100] = {0};//用于存储递归调用时的编码
class Node{
public:
    int id;//在数组中的索引
    int parent;
    int lchild;
    int rchild;
    float weight;//权重,即字符的出现频率
    char value;
    //缺省构造函数,确定成员的初始值
    Node():id(-1),parent(-1),lchild(-1),rchild(-1),weight(0),value(' '){}
    void setValue(int _id,int _lchild, int _rchild, float _weight)
    {
        id = _id;
        //parent = _parent;
        lchild = _lchild;
        rchild = _rchild;
        weight = _weight;
    }
    //重写 < 运算符,使其能够在优先队列中正确的排序
    bool operator<(const Node &a)const
    {
        return a.weight < weight;
    }
};
int n,k;
Node* haff;//一个指向Node型数组的指针
priority_queue<Node> pq;//存储节点的优先队列
vector<Node> v;
void init()
{
    char c;
    float f;
    cout<<"请输入字符的个数:"<<endl;
    cin >> n;
    k = n;
    haff = new Node[n+n+2];
    cout<<"请依次输入字符值和频率"<<endl;
    for(int i = 1;i<= n;i++)
    {
        cin >>c>>f;
        haff[i].value = c;
        haff[i].weight = f;
        haff[i].id = i;
        pq.push(haff[i]);
    }
}
void bulidHaff()
{
    while(pq.size() > 1)
    {
        Node a,b,c;
        a = pq.top();
        pq.pop();
        b = pq.top();//取出权值最小的两棵子树合并成新的子树
        pq.pop();
        k++;
        //计算新和成的子树的权重等,并放到数组中,方便确定编码方式
        haff[k].setValue(k,a.id,b.id,a.weight+b.weight);//为什么直接++k不行?
        pq.push(haff[k]);//新树插入到优先队列中
    }
}
void dfs(Node h,int num)
{
    if(h.value >= 97 && h.value <= 122)
    {
        cout<<"字符 "<<h.value<<" 的编码为:";
        for(int i = 0;i < num;i++)
            cout<<bit[i];
        cout<<endl;
        return ;
    }
    else//右子树编码为1,左子树编码为0
    {
        if(h.rchild != -1)
        {
            dfs(haff[h.rchild],num+1);
            bit[num] = 1;
        }
        if(h.lchild != -1)
        {
            dfs(haff[h.lchild],num+1);
            bit[num] = 0;
        }
    }
}
int main()
{
    init();
    bulidHaff();
    dfs(pq.top(),0);//递归调用求出字符的编码
    return 0;
}
/*测试数据
6
a 0.05
b 0.32
c 0.18
d 0.07
e 0.25
f 0.13
*/

  • 加油站问题的贪心实现
#include<bits/stdc++.h>
#define N 1001
using namespace std;
//dis数组存储加油站之间的距离,sum[i]表示存储第一个到第i个加油站间的总距离
int dis[N] = {0},n,k,sum[N] = {0};
bool flag = true;//表示是否能达到终点
int station = 0;//停靠的次数
void init()
{
    cout<<"请输入汽车满油最大行驶距离和加油站的数量:"<<endl;
    cin >> n >> k;
    cout<<"请依次输入加油站之间短距离:"<<endl;
    for(int i = 1;i <=k+1;i++)
    {
        cin >> dis[i];
        sum[i] = sum[i-1]+dis[i];
        if(sum[i] - sum[i-1] > n)//如果有两个相邻加油站之间距离大于n,则不可能到达终点
            flag = false;
    }
}
void greedy()
{
    if(!flag)
    {
        cout<<"Sorry,No Solution!"<<endl;
        return ;
    }
    //start代表上一次的停靠点,stop代表本次将要停靠的点
    int start = 0,stop;
    cout<<"停靠的加油站有:"<<endl;
    for(stop = 1;stop < k+2;stop++)
    {
        //贪心选择一个刚好汽车行驶最大距离能达到的加油站
        if(sum[stop] - sum[start] <= n && sum[stop+1] - sum[start] > n)
        {
             station++;
             start = stop;
             cout <<stop<<" ";
        }
        //最后一站是终点,停车不加油,正好sum[k+2]等于0,station不会加
    }
    cout << k+1<<endl;
}
int main()
{
    init();
    greedy();
    cout<<"最少加油的次数是: "<<station<<endl;
    for(int i = 1;i <= k+1;i++)
        cout<<sum[i]<<" ";
    return 0;
}
/*测试数据
7 7
1 2 3 4 5 1 6 6
*/

  • 图的m着色问题
//图的m着色问题
#include<bits/stdc++.h>
#define N 101
using namespace std;
int n,color,bian,m[N];//节点数,颜色数,和边的条数,m[i]表示第i个节点的颜色
int pict[N][N] = {0},ans = 0;//图的邻接矩阵
void init()
{
    cin >> n >> color >> bian;
    for(int i = 1;i <= bian;i++)
    {
        int a,b;
        cin >>a >> b;
        pict[a][b] = 1;
        pict[b][a] = 1;
    }
}
bool ok(int k)
{
    for(int j = 1;j < k;j++)
    {
        if(pict[k][j] && m[k] == m[j])
            return false;
    }
    return true;
}
void backtrack(int k)
{
    if(k > n)
    {
        cout << "第" << ++ans << "种方案:" << endl;
        for(int i = 1;i <= n;i++)
            cout << m[i] << " ";
        cout << endl;
        return ;
    }
    for(int c = 1; c <= color; c++)
    {
        m[k] = c;
        if(ok(k))
            backtrack(k+1);
        //回退时m[k]不影响前面的取值,所以不需要改回去
    }
}
int main()
{
    init();
    backtrack(1);
    return 0;
}
/*测试数据
7 3 12
1 2
1 3
1 4
2 3
2 5
3 4
3 5
4 5
4 7
5 6
5 7
6 7
*/

  • 0-1背包的回溯实现
//0-1背包问题的回溯算法实现
#include<bits/stdc++.h>
#define N 1001
using namespace std;
int n,w[N] = {0},v[N] = {0};//n见物品,第i件物品重量为w[i],价值为v[i]
int cw = 0,cv = 0,we,bestv = 0;//cw表示已经放入背包的重量,cv表示已经放入背包的价值,we表示背包的容量,bestw表示最优值即最大价值
int x[N],best[N];//x表示回溯过程中的解,best记录最优的解,1为放入,0不放
void init()
{
    cout << "请输入物品数量和背包容量,用空格分开:" <<endl;
    cin >> n >> we;
    cout << "请依次输入 " << n << " 件物品的重量和价值,用空格分开:"<<endl;
    for(int i = 1;i <= n;i++)
    {
        cin >> w[i] >> v[i];
    }
}
int Bound(int k)//上界函数,返回已放入的物品价值和剩下的价值和
{
    int sum = 0;
    for(int i = k;i <= n;i++)
        sum += v[i];
    return (cv + sum);
}
void backTrack(int k)//代表第k层
{
    if(k > n)//一直搞不懂为什么到了最后一层就一定是最优解,不用判断以前的bestv和本次bestv哪个大吗,仔细一想,能到达最后一层的情况要么n件物品全部放入,(不满足限界条件就剪纸了,到不了最后)
    {        //肯定是最大值;要么也是满足限界函数Bound(k+1) > bestv才能到达最后一层,所以肯定比上次的bestv大
        int sum = 0;
        for(int j = 1;j <= n;j++)
        {
            best[j] = x[j];
            sum += (x[j] * v[j]);
        }
        bestv = sum;
        return ;
    }
    if(cw + w[k] < we)//满足约束条件,即还能放入第k个物品,搜索左子树
    {
        x[k] = 1;
        cw += w[k];
        cv += v[k];
        cout << "cv: " << cv << endl;
        backTrack(k+1);
        cw -= v[k];
        cv -= v[k];
    }
    if(Bound(k+1) > bestv)//第k个背包不放入,如果满足上界函数也有可能得到最优解,扩展右子树
    {
        x[k] = 0;
        backTrack(k+1);
    }
}
void print()
{
    cout << "最优装包价值为:"<<bestv<<endl;
    cout << "装进背包的物品编号为:" << endl;
    for(int  i = 1;i <= n;i++)
        if(best[i])
        cout << i << " ";
}
int  main()
{
    init();
    backTrack(1);//从第一个背包开始判断
    print();
    return 0;
}
/*测试数据
5 10
2 6 5 3 4 5 2 4 3 6
*/

  • 旅行售货商问题
#include<bits/stdc++.h>
#define INF 9999
#define N 1001
using namespace std;
int n, m;
int g[N][N], x[N], best[N];//城市的邻接矩阵,路线的临时保存,最优路线
int c = 0, bestl = INF;//目前经过城市的路径和,最优路径和
void init()
{
    cout << "请输入城市数和边数:";
    cin >> n >> m;
    for(int i = 1;i <= n;i++)
    {
        x[i] = i;
        for(int j = 1;j <= n;j++)
            g[i][j] = INF;
    }
    cout << "请依次输入两个相连城市的编号和距离:" << endl;
    for(int i = 1;i <= m;i++)
    {
        int x1,x2,x3;
        cin >> x1 >> x2 >> x3;
        g[x1][x2] = g[x2][x1] = x3;
    }
}
void travel(int k)
{
    if(k > n)
    {
        if(g[x[n]][1] != INF && c+g[x[n]][1] < bestl)//最后一个节点和第一个节点有通路且,加上最后一段距离小于目前最优长度
        {
            bestl = c+g[x[n]][1];
            for(int i = 1;i <= n;i++)
                best[i] = x[i];
            return ;
        }
    }
    else
    {
        for(int j = k;j <= n;j++)
        {
            //有通路且可能产生最优解
            if(g[x[k-1]][x[j]] != INF && c + g[x[k-1]][x[j]] < bestl)
            {
                swap(x[k],x[j]);
                c += g[x[k-1]][x[k]];
                travel(k+1);
                c -= g[x[k-1]][x[k]];
                swap(x[k],x[j]);
            }
        }
    }
}
void print()
{
    cout <<"最短路径为: " << bestl << endl << "路线是:" <<endl;;
    for(int i = 1;i <= n;i++)
        cout << best[i] << "->";
    cout << "1"<< endl;
}
int main()
{
    init();
    travel(2);
    print();
    return 0;
}
/*测试数据
5 9
1 2 3
1 4 8
1 5 9
2 3 3
2 4 10
2 5 5
3 4 4
3 5 3
4 5 20
*/

趣学算法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值