算法导论 practice4

1、bellman-ford算法

对每条边松弛|V|-1次。

运行结果如下:

(实现的例子)

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #define maxnum 100
 4 #define maxint 99999
 5
 6 // 边,
 7 typedef struct Edge{
 8     int u, v;    // 起点,终点
 9     int weight;  // 边的权值
10 }Edge;
11
12 Edge edge[maxnum];     // 保存边的值
13 int  dist[maxnum];     // 结点到源点最小距离
14
15 int nodenum, edgenum, source;    // 结点数,边数,源点
16
17 // 初始化图
18 void init()
19 {
20     // 输入
21     printf("请输入结点数 边数 源点:\n");
22     scanf("%d %d %d",&nodenum, &edgenum, &source);
23     for(int i=1; i<=nodenum; ++i)
24         dist[i] = maxint;
25     dist[source] = 0;
26
27     for(int i=1; i<=edgenum; ++i)
28     {
29         scanf("%d %d %d",&edge[i].u, & edge[i].v,&edge[i].weight);
30         if(edge[i].u == source)          //注意这里设置初始情况
31             dist[edge[i].v] = edge[i].weight;
32     }
33 }
34
35 // 松弛计算
36 void relax(int u, int v, int weight)
37 {
38     if(dist[v] > dist[u] + weight)
39         dist[v] = dist[u] + weight;
40 }
41
42 bool Bellman_Ford()
43 {
44     for(int i=1; i<=nodenum-1; ++i)
45         for(int j=1; j<=edgenum; ++j)
46             relax(edge[j].u, edge[j].v, edge[j].weight);
47     bool flag = 1;
48     // 判断是否有负环路
49     for(int i=1; i<=edgenum; ++i)
50         if(dist[edge[i].v] > dist[edge[i].u] + edge[i].weight)
51         {
52             flag = 0;
53             printf("有负环路\n");
54             break;
55         }
56     printf("没有负环路\n");
57     return flag;
58
59 }
60 int main()
61 {
62     init();
63     if(Bellman_Ford())
64         for(int i = 1 ;i < nodenum; i++)
65             printf("点s->点%d:%d\n",i,dist[i]);
66     return 0;
67 }

2、All-pairs shortest path (choose one from the three algorithms)

(实现的例子)

运行结果:

 1 #include <cstdlib>
 2 #include <iostream>
 3 #define N 9999
 4 using namespace std;
 5 int l[5][5] = {{0, 3, 8, N, -4}, {N, 0, N, 1, 7}, {N, 4, 0, N, N}, {2, N, -5, 0, N}, {N, N, N, 6, 0}};
 6 int w[5][5];
 7 void print()
 8 {
 9      for(int i = 0; i < 5; i++)
10      {
11              for(int j = 0; j < 5; j++)
12                      cout << w[i][j] << " ";
13              cout << endl;
14      }
15 }
16
17 void ExtendShortestPath()
18 {
19      int t;
20      for(int i = 0; i < 5; i++)
21              for(int j = 0; j < 5; j++)
22              {
23                      t = N;
24                      for(int k = 0; k < 5; k++)//k值代表最多几条路径
25                      {
26
27                              if(l[i][j] > l[i][k] + l[k][j] && t > l[i][k] + l[k][j])
28                              {
29                                         w[i][j] = l[i][k] + l[k][j];
30                                         t = w[i][j];
31                              }
32                      }
33              }
34 }
35
36 int main(int argc, char *argv[])
37 {
38     for(int i = 0; i < 5; i++)
39     {
40             for(int j = 0; j < 5; j++)
41             {
42                             w[i][j] = l[i][j];
43             }
44     }
45     int m;
46     m = 1;
47     while(m < 4)
48     {
49             ExtendShortestPath();
50             m*=2;
51             print();
52             for(int i = 0; i <5; i++)
53             {
54                     for(int j = 0; j < 5; j++)
55                     {
56                             l[i][j] = w[i][j];
57                     }
58             }
59             cout << endl;
60     }
61
62     system("PAUSE");
63     return 0;
64 }

3、8-queen problem (back backing)

运行结果如下:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3
 4 #define max 8
 5
 6
 7 int queen[max], sum=0; /* max为棋盘最大坐标 */
 8
 9 void show() /* 输出所有皇后的坐标 */
10 {
11     int i;
12     for(i = 0; i < max; i++)
13     {
14          printf("(%d,%d) ", i, queen[i]);
15     }
16     printf("\n");
17     sum++;
18 }
19
20 int check(int n) /* 检查当前列能否放置皇后 */
21 {
22     int i;
23     for(i = 0; i < n; i++) /* 检查横排和对角线上是否可以放置皇后 */
24     {
25         if(queen[i] == queen[n] || abs(queen[i] - queen[n]) == (n - i))
26         {
27             return 1;
28         }
29     }
30     return 0;
31 }
32
33 void put(int n) /* 回溯尝试皇后位置,n为横坐标 */
34 {
35     int i;
36     for(i = 0; i < max; i++)
37     {
38         queen[n] = i; /* 将皇后摆到当前循环到的位置 */
39         if(!check(n))
40         {
41             if(n == max - 1)
42             {
43                 show(); /* 如果全部摆好,则输出所有皇后的坐标 */
44             }
45             else
46             {
47                 put(n + 1); /* 否则继续摆放下一个皇后 */
48             }
49         }
50     }
51 }
52
53 int main()
54 {
55     put(0); /* 从横坐标为0开始依次尝试 */
56     printf("\n总方法数:%d", sum);
57     system("pause");
58     return 0;
59 }

4、0-1 knapsack problem (back tracking)

对一组数据,有两种可能:选或不选,在树种用左右字数表示。

使用递归,在遍历完n个数时,判断最终的数是否比最佳价值大,如比最佳大,则把值付给besrv。

上界函数:当前的价值cw+剩余可容纳的最大价值<=当前最优解

运行结果如下:

  1 #include <stdio.h>
  2 #include <conio.h>
  3
  4 int n;//物品数量
  5 double c;//背包容量
  6 double v[100];//各个物品的价值
  7 double w[100];//各个物品的重量
  8 double cw = 0.0;//当前背包重量
  9 double cp = 0.0;//当前背包中物品价值
 10 double bestp = 0.0;//当前最优价值
 11 double perp[100];//单位物品价值排序后
 12 int order[100];//物品编号
 13 int put[100];//设置是否装入
 14
 15 //计算上界函数
 16 double bound(int i)
 17 {
 18     double leftw= c-cw;
 19     double b = cp;
 20     while(i<=n&&w[i]<=leftw)
 21     {
 22         leftw-=w[i];
 23         b+=v[i];
 24         i++;
 25     }
 26     if(i<=n)
 27     b+=v[i]/w[i]*leftw;
 28     return b;
 29 }
 30
 31 //按单位价值排序
 32 void knapsack()
 33 {
 34     int i,j;
 35     int temporder = 0;
 36     double temp = 0.0;
 37     for(i=1;i<=n;i++ )
 38         perp[i]=v[i]/w[i];
 39     for(i=1;i<=n-1;i++)
 40     {
 41         for(j=i+1;j<=n;j++)
 42             if(perp[i]<perp[j])
 43             {
 44                 temp = perp[i];
 45                 perp[i]=perp[i];
 46                 perp[j]=temp;
 47                 temporder=order[i];
 48                 order[i]=order[j];
 49                 order[j]=temporder;
 50                 temp = v[i];
 51                 v[i]=v[j];
 52                 v[j]=temp;
 53                 temp=w[i];
 54                 w[i]=w[j];
 55                 w[j]=temp;
 56             }
 57     }
 58 }
 59
 60 //回溯函数
 61 void backtrack(int i)
 62 {
 63     double bound(int i);
 64     if(i>n)
 65     {
 66         bestp = cp;
 67         return;
 68     }
 69     if(cw+w[i]<=c)
 70     {
 71         cw+=w[i];
 72         cp+=v[i];
 73         put[i]=1;
 74         backtrack(i+1);
 75         cw-=w[i];
 76         cp-=v[i];
 77     }
 78     if(bound(i+1)>bestp)//符合条件搜索右子数
 79         backtrack(i+1);
 80 }
 81
 82 int main()
 83 {
 84     int i;
 85     printf("请输入物品的数量和容量:");
 86     scanf("%d %lf",&n,&c);
 87     printf("请输入物品的重量和价值:");
 88     for(i=1;i<=n;i++)
 89     {
 90         printf("第%d个物品的重量和价值:",i);
 91     scanf("%lf",&w[i],&v[i]);
 92     printf("第%d个物品的价值:",i);
 93     scanf("%lf",&v[i]);
 94     order[i]=i;
 95     }
 96     knapsack();
 97     backtrack(1);
 98     printf("最有价值为:%lf\n",bestp);
 99     printf("需要装入的物品编号是:");
100     for(i=1;i<=n;i++)
101     {
102         if(put[i]==1)
103         printf("%d ",order[i]);
104     }
105     return 0;
106 }
时间: 2024-11-05 18:42:59

算法导论 practice4的相关文章

算法导论学习之插入排序+合并排序

最近准备花时间把算法导论详细的看一遍,强化一下算法和数据结构的基础,将一些总结性的东西写到博客上去. 一.插入排序 算法思想:如果一个数组A,从A[1–n-1]都是有序的,然后我们将A[n]插入到A[1–n-1]的某个合适的位置上去那么就可以保证A[1–n]都是有序的.这就是插入排序的思想:具体实现的时候我们将数组的第一个元素看出有序,然后从第二个元素开始按照上面的步骤进行插入操作,直到插入最后一个元素,然后整个数组都是有序的了. 时间复杂度分析:代码中有两重for循环,很容易看出时间复杂度是n

算法导论——lec 13 贪心算法与图上算法

之前我们介绍了用动态规划的方法来解决一些最优化的问题.但对于有些最优化问题来说,用动态规划就是"高射炮打蚊子",采用一些更加简单有效的方法就可以解决.贪心算法就是其中之一.贪心算法是使所做的选择看起来是当前最佳的,期望通过所做的局部最优选择来产生一个全局最优解. 一. 活动选择问题 [问题]对几个互相竞争的活动进行调度:活动集合S = {a1, a2, ..., an},它们都要求以独占的方式使用某一公共资源(如教室),每个活动ai有一个开始时间si和结束时间fi ,且0 ≤ si &

算法导论--图的遍历(DFS与BFS)

转载请注明出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51897538 图的遍历就是从图中的某个顶点出发,按某种方法对图中的所有顶点访问且仅访问一次.为了保证图中的顶点在遍历过程中仅访问一次,要为每一个顶点设置一个访问标志.通常有两种方法:深度优先搜索(DFS)和广度优先搜索(BFS).这两种算法对有向图与无向图均适用. 以下面无向图为例: 1.深度优先搜索(DFS) 基本步骤: 1.从图中某个顶点v0出发,首先访问v

算法导论8:数据结构——栈 2016.1.8

栈在暑假的时候接触过了,当时还写了个计算器,用的中缀表达式后缀表达式的栈操作. http://www.cnblogs.com/itlqs/p/4749998.html 今天按照算法导论上的讲解规范了一下代码.主要是栈的初始化.判断空栈.入栈.出栈.遍历栈. #include<stdio.h> #define MAXTOP 10 struct _stack { int top; int num[MAXTOP+1]; }s; void init(struct _stack &S) { S.

红黑树&mdash;&mdash;算法导论(15)

1. 什么是红黑树 (1) 简介     上一篇我们介绍了基本动态集合操作时间复杂度均为O(h)的二叉搜索树.但遗憾的是,只有当二叉搜索树高度较低时,这些集合操作才会较快:即当树的高度较高(甚至一种极端情况是树变成了1条链)时,这些集合操作并不比在链表上执行的快.     于是我们需要构建出一种"平衡"的二叉搜索树.     红黑树(red-black tree)正是其中的一种.它可以保证在最坏的情况下,基本集合操作的时间复杂度是O(lgn). (2) 性质     与普通二叉搜索树不

算法导论5.3-3

转自风清云淡的博客,他给出的解法非常的妙. 问题: 描述RANDOM(a,b)的过程的一种实现,它只调用RANDOM(0,1).作为a和b的函数,你的程序的期望运行时间是多少?注:RANDOM(0,1)以等概率输出0或者1,      要求RANDOM(a,b)以等概率输出[a,b]之间的数(整数) 解决方案: 1,取 n=b-a+1,取最小的正整数m,使得 2^m >= n         2,调用RANDOM(0,1),输出m-bit位整数N   (  N >= 0 and N <=

算法导论第十二章 二叉搜索树

一.二叉搜索树概览 二叉搜索树(又名二叉查找树.二叉排序树)是一种可提供良好搜寻效率的树形结构,支持动态集合操作,所谓动态集合操作,就是Search.Maximum.Minimum.Insert.Delete等操作,二叉搜索树可以保证这些操作在对数时间内完成.当然,在最坏情况下,即所有节点形成一种链式树结构,则需要O(n)时间.这就说明,针对这些动态集合操作,二叉搜索树还有改进的空间,即确保最坏情况下所有操作在对数时间内完成.这样的改进结构有AVL(Adelson-Velskii-Landis)

算法导论--动态规划(装配线调度)

装配线问题: 某个工厂生产一种产品,有两种装配线选择,每条装配线都有n个装配站.可以单独用,装配线1或2加工生产,也可以使用装配线i的第j个装配站后,进入另一个装配线的第j+1个装配站继续生产.现想找出通过工厂装配线的最快方法. 装配线i的第j个装配站表示为Si,j,在该站的装配时间是ai,j 如果从 Si,j装配站生产后,转移到另一个生产线继续生产所耗费的时间为ti,j 进入装配线花费时间ei,完成生产后离开装配线所耗费时间为xi 令f*表示通过生产所有路线中的最快的时间 令fi[j]表示从入

算法导论CLRS答案

目前正在编写算法导论答案,欢迎大家follow me at mygithub 刚完成第9章,中位数和顺序统计学 正在编写第13章,红黑树 想要参与的朋友可以告诉我想要编写的章节,开个branch给你------