码迷,mamicode.com
首页 > 编程语言 > 详细

《趣学算法》第二章 贪心算法源代码

时间:2020-09-16 12:17:10      阅读:30      评论:0      收藏:0      [点我收藏+]

标签:als   哈夫曼   大于等于   最小值   秘书   fine   ret   end   path   

贪心算法相关代码实现

以下代码搬运自《趣学算法》实战演练

1、加勒比海盗船——最优装载问题

#include <iostream>
#include <algorithm>
const int N=1000005;
using namespace std;

double w[N]; //古董的重量数组
int main()
{
    double c;
    int n;
    cout<<"请输入载重量c及古董个数n:"<<endl;
    cin>>c>>n;
    cout<<"请输入每个古董的重量,用空格分开: "<<endl;
    for(int i=0;i<n;i++)
    {
      cin>>w[i]; //输入每个物品重量
    }
    sort(w,w+n); //按古董重量升序排序
    double tmp=0.0;
    int ans=0; // tmp为已装载到船上的古董重量,ans为已装载的古董个数
    for(int i=0;i<n;i++)
{
      tmp+=w[i];
     if(tmp<=c)
     ans++;
      else
        break;
}
    cout<<"能装入的古董最大数量为Ans=";
    cout<<ans<<endl;
    return 0;
}

//可以输出古董编号
/**
struct antique{
    int id; //古董的编号
    double w; //古董的重量
}s[N];
bool cmp(antique a, antique b)//比较函数
{
    return a.w < b.w; //指明按照古董重量升序排列
}
int main()
{
    double c;
    int n;
    cout<<"请输入载重量c及古董个数n:"<<endl;
    cin>>c>>n;
    cout<<"请输入每个古董的重量,用空格分开: "<<endl;
    for(int i=0;i<n;i++)
    {
      s[i].id=i+1;
      cin>>s[i].w; //输入每个古董重量,用空格隔开
    }
    sort(s,s+n,cmp);
    double tmp=0.0;
    int ans =0;  //ans记录已经装载的古董个数,tmp代表装载到船上的古董的重量
    for(int i=0;i<n;i++)
    {
     tmp += s[i].w;
     if(tmp<=c)
       ans ++;
    else
       break;
     }
    cout<<"能装入的古董最大数量为Ans = ";
    cout<<ans<<endl;
    cout<<"装入的古董编号为";
    for(int i=0;i<ans;i++)
    {
      cout<<s[i].id<<" ";
    }
    return 0;
}
**/

2、阿里巴巴与四十大盗——背包问题

//program 2-2
#include<iostream>
#include<algorithm>
using namespace std;
const int M=1000005;
struct three{
    double w;//每个宝物的重量
    double v;//每个宝物的价值
    double p;//性价比
}s[M];
bool cmp(three a,three b)
{
    return a.p>b.p;//根据宝物的单位价值从大到小排序
}
int main()
{
    int n;//n 表示有n个宝物
    double m ;//m 表示毛驴的承载能力
    cout<<"请输入宝物数量n及毛驴的承载能力m :"<<endl;
    cin>>n>>m;
    cout<<"请输入每个宝物的重量和价值,用空格分开: "<<endl;
    for(int i=0;i<n;i++)
    {
        cin>>s[i].w>>s[i].v;
        s[i].p=s[i].v/s[i].w;//每个宝物单位价值
    }
    sort(s,s+n,cmp);
    double sum=0.0;// sum 表示贪心记录运走宝物的价值之和
    for(int i=0;i<n;i++)//按照排好的顺序贪心
    {
        if( m>s[i].w )//如果宝物的重量小于毛驴剩下的承载能力
        {
            m-=s[i].w;
            sum+=s[i].v;
        }
        else//如果宝物的重量大于毛驴剩下的承载能力
        {
            sum+=m*s[i].p;//部分装入
            break;
        }
    }
    cout<<"装入宝物的最大价值Maximum value="<<sum<<endl;//输出装入宝物的最大价值
    return 0;
}

3、高级钟点秘书——会议安排

//program 2-3
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
struct Meet
{
    int beg;   //会议的开始时间
    int end;   //会议的结束时间
    int num;   //记录会议的编号
}meet[1000];   //会议的最大个数为1000

class setMeet{
  public:
    void init();
    void solve();
  private:
    int n,ans; // n:会议总数 ans: 最大的安排会议总数
};

//读入数据
void setMeet::init()
{
    int s,e;
    cout <<"输入会议总数:"<<endl;
    cin >> n;
    int i;
    cout <<"输入会议的开始时间和结束时间,以空格分开:"<<endl;
    for(i=0;i<n;++i)
    {
        cin>>s>>e;
        meet[i].beg=s;
        meet[i].end=e;
        meet[i].num=i+1;
    }
}

bool cmp(Meet x,Meet y)
{
    if (x.end == y.end)
        return x.beg > y.beg;
    return x.end < y.end;
}

void setMeet::solve()
{
    sort(meet,meet+n,cmp);    //对会议按结束时间排序
    cout <<"排完序的会议时间如下:"<<endl;
    int i;
    cout <<"会议编号:"<<"  开始时间 "<<" 结束时间"<<endl;
    for(i=0; i<n;i++)
    {
      cout<< "   " << meet[i].num<<"\t\t"<<meet[i].beg <<"\t"<< meet[i].end << endl;
    }
    cout <<"-------------------------------------------------"<<endl;
    cout << "选择的会议的过程:" <<endl;
    cout <<"  选择第"<< meet[0].num<<"个会议" << endl;//选中了第一个会议
    ans=1;
    int last = meet[0].end;  //记录刚刚被选中会议的结束时间
    for( i = 1;i < n;++i)
    {
        if(meet[i].beg>=last)
        {            //如果会议i开始时间大于等于最后一个选中的会议的结束时间
           ans++;
           last = meet[i].end;
           cout <<"  选择第"<<meet[i].num<<"个会议"<<endl;
         }
    }
    cout <<"最多可以安排" <<ans << "个会议"<<endl;
}

int main()
{
  setMeet sm;
  sm.init();//读入数据
  sm.solve();//贪心算法求解
  return 0;
}

4、一场说走就走的旅行——最短路径

//栈实现
#include <iostream>
#include<windows.h>
#include<stack>
using namespace std;
const int N=100; // 城市的个数可修改
const int INF=1e7; // 无穷大10000000
int map[N][N],dist[N],p[N],n,m;//n城市的个数,m为城市间路线的条数
bool flag[N]; //如果s[i]等于true,说明顶点i已经加入到集合S;否则顶点i属于集合V-S
void Dijkstra(int u)
{
   for(int i=1; i<=n; i++)
    {
     dist[i] =map[u][i]; //初始化源点u到其他各个顶点的最短路径长度
     flag[i]=false;
     if(dist[i]==INF)
       p[i]=-1; //源点u到该顶点的路径长度为无穷大,说明顶点i与源点u不相邻
     else
       p[i]=u; //说明顶点i与源点u相邻,设置顶点i的前驱p[i]=u
     }
    dist[u] = 0;
    flag[u]=true;   //初始时,集合S中只有一个元素:源点u
    for(int i=1; i<=n; i++)
     {
        int temp = INF,t = u;
        for(int j=1; j<=n; j++) //在集合V-S中寻找距离源点u最近的顶点t
          if(!flag[j]&&dist[j]<temp)
           {
            t=j;
            temp=dist[j];
          }
        if(t==u) return ; //找不到t,跳出循环
        flag[t]= true;  //否则,将t加入集合
        for(int j=1;j<=n;j++)//更新与t相邻接的顶点到源点u的距离
          if(!flag[j]&& map[t][j]<INF)
            if(dist[j]>(dist[t]+map[t][j]))
             {
               dist[j]=dist[t]+map[t][j] ;
               p[j]=t ;
             }
       }
}
void findpath(int u)
{
  int x;
  stack<int>s;
  cout<<"源点为:"<<u<<endl;
  for(int i=1;i<=n;i++)
  {
    x=p[i];
    while(x!=-1)
    {
      s.push(x);
      x=p[x];
    }
    cout<<"源点到其它各顶点最短路径为:";
    while(!s.empty())
    {
      cout<<s.top()<<"--";
      s.pop();
    }
    cout<<i<<";最短距离为:"<<dist[i]<<endl;
  }
}

int main()
{
        int u,v,w,st;
        system("color 0d");
        cout << "请输入城市的个数:"<<endl;cin >> n;
        cout << "请输入城市之间的路线的个数:"<<endl;cin >>m;
        cout << "请输入城市之间的路线以及距离:"<<endl;
        for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
          {
             map[i][j]=INF;//初始化邻接矩阵为无穷大
          }
        while(m--)
        {
            cin >> u >> v >> w;
            map[u][v] =min(map[u][v],w); //邻接矩阵储存,保留最小的距离
        }
        cout <<"请输入小明所在的位置:"<<endl; ;
        cin >> st;
        Dijkstra(st);
        cout <<"小明所在的位置:"<<st<<endl;
        for(int i=1;i<=n;i++)
        {
             cout <<"小明:"<<st<<" - "<<"要去的位置:"<<i;
             if(dist[i] == INF)
               cout << "sorry,无路可达"<<endl;
             else
               cout << " 最短距离为:"<<dist[i]<<endl;
         }

         findpath(st);
         return 0;
}
//队列实现
#include <queue>
#include <iostream>
#include<cstring>
#include<windows.h>
using namespace std;
const int N = 100; // 城市的个数可修改
const int INF = 1e7; // 无穷大
int map[N][N],dist[N],n,m;
int flag[N];
struct  Node{
    int u,step;
    Node(){};
    Node(int a,int sp){
        u=a;step=sp;
    }
    bool operator < (const  Node& a)const{  // 重载 <
        return step>a.step;
    }
};
void Dijkstra(int st){
    priority_queue <Node> Q;  // 优先队列优化
    Q.push(Node(st,0));
    memset(flag,0,sizeof(flag));//初始化flag数组为0
    for(int i=1;i<=n;++i)
      dist[i]=INF; // 初始化所有距离为,无穷大
    dist[st]=0;
    while(!Q.empty())
    {
        Node it=Q.top();//优先队列队头元素为最小值
        Q.pop();
        int t=it.u;
        if(flag[t])//说明已经找到了最短距离,该结点是队列里面的重复元素
            continue;
        flag[t]=1;
        for(int i=1;i<=n;i++)
        {
            if(!flag[i]&&map[t][i]<INF){ // 判断与当前点有关系的点,并且自己不能到自己
                if(dist[i]>dist[t]+map[t][i])
                {   // 求距离当前点的每个点的最短距离,进行松弛操作
                    dist[i]=dist[t]+map[t][i];
                    Q.push(Node(i,dist[i]));// 把更新后的最短距离压入优先队列,注意:里面的元素有重复
                 }
            }
        }
    }
}
int main()
{
        int u,v,w,st;
        system("color 0d");//设置背景及字体颜色
        cout << "请输入城市的个数:"<<endl;
        cin >> n;
        cout << "请输入城市之间的路线的个数:"<<endl;
        cin >>m;
        for(int i=1;i<=n;i++)//初始化图的邻接矩阵
          for(int j=1;j<=n;j++)
          {
              map[i][j]=INF;//初始化邻接矩阵为无穷大
          }
        cout << "请输入城市之间u,v的路线以及距离w:"<<endl;
        while(m--)
        {
            cin>>u>>v>>w;
            map[u][v]=min(map[u][v],w); //邻接矩阵储存,保留最小的距离
        }
        cout<<"请输入小明所在的位置:"<<endl; ;
        cin>>st;
        Dijkstra(st);
        cout <<"小明所在的位置:"<<st<<endl;
        for(int i=1;i<=n;i++)
        {
             cout <<"小明:"<<st<<"--->"<<"要去的位置:"<<i;
             if(dist[i]==INF)
                cout << "sorry,无路可达"<<endl;
             else
                cout << " 最短距离为:"<<dist[i]<<endl;
        }
    return 0;
}



5、神秘电报密码——哈夫曼编码

//program 2-5
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXBIT    100
#define MAXVALUE  10000
#define MAXLEAF   30
#define MAXNODE   MAXLEAF*2 -1

typedef struct
{
    double weight;
    int parent;
    int lchild;
    int rchild;
    char value;
} HNodeType;        /* 结点结构体 */

typedef struct
{
    int bit[MAXBIT];
    int start;
} HCodeType;        /* 编码结构体 */
HNodeType HuffNode[MAXNODE]; /* 定义一个结点结构体数组 */
HCodeType HuffCode[MAXLEAF];/* 定义一个编码结构体数组*/
/* 构造哈夫曼树 */
void HuffmanTree (HNodeType HuffNode[MAXNODE],  int n){
    /* i、j: 循环变量,m1、m2:构造哈夫曼树不同过程中两个最小权值结点的权值,
       x1、x2:构造哈夫曼树不同过程中两个最小权值结点在数组中的序号。*/
    int i, j, x1, x2;
    double m1,m2;
    /* 初始化存放哈夫曼树数组 HuffNode[] 中的结点 */
    for (i=0; i<2*n-1;i++)
    {
        HuffNode[i].weight=0;//权值
        HuffNode[i].parent=-1;
        HuffNode[i].lchild=-1;
        HuffNode[i].rchild=-1;
    }
    /* 输入 n 个叶子结点的权值 */
    for (i=0; i<n; i++)
    {
        cout<<"Please input value and weight of leaf node "<<i+1<<endl;
        cin>>HuffNode[i].value>>HuffNode[i].weight;
    }
    /* 构造 Huffman 树 */
    for (i=0; i<n-1; i++)
    {//执行n-1次合并
         m1=m2=MAXVALUE;
         /* m1、m2中存放两个无父结点且结点权值最小的两个结点 */
        x1=x2=0;
        /* 找出所有结点中权值最小、无父结点的两个结点,并合并之为一棵二叉树 */
        for (j=0;j<n+i;j++)
        {
            if (HuffNode[j].weight<m1&&HuffNode[j].parent==-1)
            {
                m2 = m1;
                x2 = x1;
                m1 = HuffNode[j].weight;
                x1 = j;
            }
            else if (HuffNode[j].weight < m2 && HuffNode[j].parent==-1)
            {
                m2=HuffNode[j].weight;
                x2=j;
            }
        }
        /* 设置找到的两个子结点 x1、x2 的父结点信息 */
        HuffNode[x1].parent  = n+i;
        HuffNode[x2].parent  = n+i;
        HuffNode[n+i].weight = m1+m2;
        HuffNode[n+i].lchild = x1;
        HuffNode[n+i].rchild = x2;
        cout<<"x1.weight and x2.weight in round "<<i+1<<"\t"<<HuffNode[x1].weight<<"\t"<<HuffNode[x2].weight<<endl; /* 用于测试 */
    }
}
/* 哈夫曼树编码 */
void HuffmanCode(HCodeType HuffCode[MAXLEAF],  int n){
    HCodeType cd;       /* 定义一个临时变量来存放求解编码时的信息 */
    int i,j,c,p;
    for(i=0;i<n;i++)
    {
        cd.start=n-1;
        c=i;
        p=HuffNode[c].parent;
        while(p!=-1)
        {
            if(HuffNode[p].lchild==c)
                cd.bit[cd.start]=0;
            else
                cd.bit[cd.start]=1;
            cd.start--;        /*前移一位 */
            c=p;
            p=HuffNode[c].parent;    /* 设置下一循环条件 */
        }
        /* 把叶子结点的编码信息从临时编码cd中复制出来,放入编码结构体数组 */
        for (j=cd.start+1; j<n; j++)
           HuffCode[i].bit[j]=cd.bit[j];
        HuffCode[i].start=cd.start;
    }
}
int main()
{
    int i,j,n;
    cout<<"Please input n:"<<endl;
    cin>>n;
    HuffmanTree(HuffNode,n);  //构造哈夫曼树
    HuffmanCode(HuffCode,n);  // 哈夫曼树编码
    //输出已保存好的所有存在编码的哈夫曼编码
    for(i=0;i<n;i++)
    {
        cout<<HuffNode[i].value<<": Huffman code is: ";
        for(j=HuffCode[i].start+1;j<n;j++)
            cout<<HuffCode[i].bit[j];
        cout<<endl;
    }
    return 0;
}

6、沟通无限校园网——最小生成树

//program 2-7
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100;
int nodeset[N];
int n, m;
struct Edge {
    int u;
    int v;
    int w;
}e[N*N];
bool comp(Edge x, Edge y) {
    return x.w < y.w;
}
void Init(int n)
{
    for(int i = 1; i <= n; i++)
        nodeset[i] = i;
}
int Merge(int a, int b)
{
    int p = nodeset[a];
    int q = nodeset[b];
    if(p==q) return 0;
    for(int i=1;i<=n;i++)//检查所有结点,把集合号是q的改为p
    {
      if(nodeset[i]==q)
        nodeset[i] = p;//a的集合号赋值给b集合号
    }
    return 1;
}
int Kruskal(int n)
{
    int ans = 0;
    for(int i=0;i<m;i++)
        if(Merge(e[i].u, e[i].v))
        {
            ans += e[i].w;
            n--;
            if(n==1)
                return ans;
        }
    return 0;
}
int main() {
        cout <<"输入结点数n和边数m:"<<endl;
        cin >> n >> m;
        Init(n);
        cout <<"输入结点数u,v和边值w:"<<endl;
        for(int i=1;i<=m;i++)
            cin >> e[i].u>> e[i].v >>e[i].w;
        sort(e, e+m, comp);
        int ans = Kruskal(n);
        cout << "最小的花费是:" << ans << endl;
    return 0;
}


//program 2-7-1
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 100;
int father[N];
int n, m;

struct Edge {
    int u;
    int v;
    int w;
}e[N*N];

bool comp(Edge x, Edge y) {
    return x.w < y.w;
}

void Init(int n)
{
    for(int i = 1; i <= n; i++)
        father[i] = i;
}

int Find(int x)
{
    if(x != father[x])
        father[x] = Find(father[x]);
    return father[x];
}

int Merge(int a, int b)
{
    int p = Find(a);
    int q = Find(b);
    if(p==q) return 0;
    if(p > q)
        father[p] = q;//小的赋值给大的集合号
    else
        father[q] = p;
    return 1;
}

int Kruskal(int n)
{
    int ans = 0;
    for(int i=0;i<m;i++)
        if(Merge(e[i].u, e[i].v))
        {
            ans += e[i].w;
            n--;
            if(n==1)
                return ans;
        }
    return 0;
}

int main() {
        cout <<"输入结点数n和边数m:"<<endl;
        cin >> n >> m;
        Init(n);
        cout <<"输入结点数u,v和边值w:"<<endl;
        for(int i=1;i<=m;i++)
            cin>>e[i].u>>e[i].v>>e[i].w;
        sort(e, e+m, comp);
        int ans = Kruskal(n);
        cout << "最小的花费是:" << ans << endl;
    return 0;
}

《趣学算法》第二章 贪心算法源代码

标签:als   哈夫曼   大于等于   最小值   秘书   fine   ret   end   path   

原文地址:https://www.cnblogs.com/self-confidence/p/13603491.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!