0 Basic Greedy algorithm

Source: Internet
Author: User
Tags radar

This article in the writing process reference a lot of information, can not be enumerated, but also forgive me. The definition of the
greedy algorithm: The
greedy algorithm means that when solving a problem, it always makes the best choice in the present. That is to say, not from the overall optimal consideration, only to make a sense of the local optimal solution. Greedy algorithm is not to all problems can get the overall optimal solution, the key is the choice of greedy strategy, the choice of greedy strategy must have no effect, that a state of the previous process will not affect the future state, only related to the current state.
The general steps to solve the problem are:
1. Set up mathematical models to describe problems;
2. Divide the problem of solving into several sub-problems;
3. To solve each sub-problem, the local optimal solution of sub-problem is obtained.
4. The local optimal solution of the problem is used to synthesize a solution to the original problem.
If you know more about dynamic planning, you'll find similarities between them. Most of the problems of optimal solution can be divided into sub-problems, the traversal of the solution space as a pair of problem tree traversal, then a certain form of the whole tree traversal can find the optimal solution, in most cases this is not feasible. Greedy algorithm and dynamic programming are essentially a pruning of pairs of problem trees, and one of the properties that both algorithms require is the optimality of sub-problems (the solution of each sub-problem that makes up the optimal solution, which is certainly optimal for the sub-problem itself). The dynamic programming method represents the general solution of this kind of problem, we construct the sub-problem from the bottom up, the root of each subtree, the value of each of the following leaves, and the optimal value as its own value, the other values discarded. The greedy algorithm is a special case of the dynamic programming method, it can be proved that the value of the root of each subtree does not depend on the value of the leaves below, but only depends on the condition of the current problem. In other words, you can find out the value of this node without needing to know the condition of all the subtrees of a node. Because of this characteristic of the greedy algorithm, it does not need the bottom-up to solve the spatial tree, but only needs to start from the root, chooses the best path, has been able to go in the end.
Not much to say, let's look at a few concrete examples to understand it slowly:
1. Activity selection Question
  This is an example of the introduction to algorithms, which is also a very classic question. There are n activities that need to use the same classroom on the same day A1,a2,..., an, the classroom can only be used by one activity at a time. Each active Ai has a start time Si and an end time of fi. Once selected, the active AI occupies the half-open time interval [Si,fi]. If [Si,fi] and [sj,fj] do not overlap, AI and AJ two activities can be scheduled on this day. The problem is to arrange these activities so that as many activities as possible can be held in a non-conflicting way. For example, the activity set S is shown, where each activity is ordered monotonically by the end time.

Consider the method of using greedy algorithm. For convenience, we use lines of different colors to represent each activity, the length of the line is the time period occupied by the activity, the blue line represents the activity we have chosen, and the red line indicates that we have no selected activity.
If we choose the earliest activity of the start time each time, we cannot get the optimal solution:

If we choose the activity with the shortest duration, we cannot get the optimal solution:

It can be proved by mathematical induction that our greedy strategy should be the earliest activity at the end time of each selection. Intuitively, it is also well understood that the selection of compatible activities in this way leaves as much time as possible for the non-scheduled activities. This is also the reason for the monotonous increment of activities by the end time.

 1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 using namespace std; 5 int N; 6 struct ACT 7 {8 int start; 9 int end;10}act[100010];11-BOOL CMP (ACT A,act b) {return a.end<  B.end;   () + int greedy_activity_selector () + {num=1,i=1;  for (int j=2;j<=n;j++) {act[j].start>=act[i].end) at $ i=j;  num++; () +} num;29 return}30 int main () (), {$ int t;34 scanf ("%d", &t); t--) ("%d", &n), scanf (int i=1;i<=n;i++) ("scanf%lld", &act[i].start,&act[i].end);}42 act[0].start=-1;43 act[0].end=-1;44 sort (act+1, ACT+N+1,CMP);  int Res=greedy_activity_selector (); cout<<res<<endl; }48} 

2. Coin change Issue
This problem is more common in our daily life. It is assumed that banknotes of $1, $2, $5, $10, $20, $50 and $100 respectively have C0, C1, C2, C3, C4, C5, C6 Zhang. Now it's time to pay K yuan with this money, at least how many banknotes? With the idea of a greedy algorithm, it is clear that every step is as large as possible with a note of the face. This is what we do naturally in our daily lives. In the program, the value is sorted in order from small to large in advance.

1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 const int n=7;  5 int count[n]={3,0,2,1,0,3,5}; 6 int value[n]={1,2,5,10,20,50,100}; 7    8 int solve (int money)  9 {ten     int num=0;11 for     (int i=n-1;i>=0;i--)     {int         c=min (money/ Value[i],count[i]);         money=money-c*value[i];15         num+=c;16     }17     if (money>0) num=-1;18     return num;19}20  int main () {     26 int money;24     cin>>money;25     int res=solve (money)     if (res!=-1) cout<<res<<endl;27     else cout<< "NO" <<endl;28}

3. More on knapsack problem
We have talked about three basic knapsack problems in the zero-based dynamic planning: 01 Backpack, part backpack, full backpack. It is easy to prove that knapsack problem cannot use greedy algorithm. However, we consider a knapsack problem: When you select item I into the backpack, you can select a part of the item, not necessarily all in the backpack. Then the greedy algorithm can be used to solve the problem. Calculate the unit weight value of each item as the basis of the greedy choice, select the item with the highest value of unit weight, put as much of the item into the backpack as possible, and follow this strategy until the backpack fills up. The reason why the greedy choice can't get the best solution in the 01 knapsack problem is that the greedy choice can't guarantee that the backpack will be fully filled, and some of the vacant backpack space can reduce the value of the backpack space per kilogram. In the program has already in advance the unit weight value according to from the big to the small order.

 1 #include <iostream> 2 using namespace std;   3 const int n=4;   4 void knapsack (float m,float v[],float w[],float x[]); 5 6 int Main () 7 {8 float m=50; 9//backpack can hold the weight of the float w[]={0,10,30,20,5};11//weight of each item F  Loat v[]={0,200,400,100,10};  13//value of each item: x[n+1]={0};  15//array of recorded results knapsack (M,V,W,X);  cout<< "Choose the proportion of items loaded:" <<endl;  for (int i=1;i<=n;i++) cout<< "[" <<i<<]: "<<x[i]<<endl;  [+] void knapsack (float m,float v[],float w[],float x[]) (+)   24//Item whole piece is loaded under for (i=1;i<=n;i++)-(w[i]>m) break;  X[i]=1;  M-=w[i];   30} 31//Item part is loaded with the IF (i<=n) x[i]=m/w[i]; (+} 
)

4. Multi-Machine scheduling problem
A set of jobs consisting of n jobs that can be processed by the same machine as the M-Unit. It is required to give a job scheduling scheme so that the N jobs given are completed in the shortest possible time by M machine processing. Jobs cannot be split into smaller sub-jobs, and each job can be processed on any machine. This problem is NP complete problem, there is no effective solution (to find the optimal solution), but the greedy selection strategy can be used to design a better approximation algorithm (to find suboptimal solution). When N<=m, the job time interval is assigned to the job, and when N>m, the n jobs are sorted first from the largest to the smaller, and then the jobs are assigned to the idle processor in this order. That is, from the rest of the work, select the longest processing time, and then select the processing time of the second, until all the work is finished, or the machine can no longer handle other jobs. If we were to assign to the idle machine every job that had the shortest processing time, then all the other jobs would have to be processed, which would be less efficient. The size relationship between N and M is not discussed in the following code, and the two cases are merged together.

 1 #include <iostream> 2 #include <algorithm> 3 using namespace std;   4 int speed[10010];   5 int mintime[110];  6 7 BOOL CMP (const int &X,CONST int &y) 8 {9 return x>y;         Ten} one and one int main (): {+ int n,m;  memset (speed,0,sizeof (speed));  memset (mintime,0,sizeof (mintime));  cin>>n>>m;  for (int i=0;i<n;++i) cin>>speed[i];  Sort (speed,speed+n,cmp);   (int i=0;i<n;++i) {*min_element (mintime,mintime+m) +=speed[i]; Cout<<*max_element (mintime,mintime+m) <<endl; 

5. Boat Crossing problem
POJ1700 is a classic problem of greedy calculation law. The main idea is that there is only one ship, can multiply 2 people, the speed of the ship is 2 slower than the speed of a person, the past will need a person to draw back the ship, ask to put n individuals to the other side, at least how long. The time required for everyone to cross the river first is sorted in ascending order, and we consider sending the two travelers who need the most time to cross the river to the other side, in two ways:
1. The fastest and the fastest to cross the river, and then the fastest to draw back the ship, the second slow and slowest crossing the river, and then the next quick to draw back the ship, the time required: t[0]+2*t[1]+t[n-1];
2. The fastest and slowest river crossing, and then the fastest to draw back the ship, the fastest and the next slow river, and then the fastest to draw back the ship, the time required is: 2*t[0]+t[n-2]+t[n-1].
You'll know that other things will take more time. Each time the longest two people are transported without affecting others, the problem has the nature of the greedy substructure.
AC Code:

1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4  5 int main () 6 {7     int a[1000],t,n,sum; 8     scanf ("%d", &t), 9 while     (t--)     {one         scanf ("%d", &n),         sum=0;13 for         (int i=0;i<n;i++) scanf ("%d", &a[i]), and         (n>3)             Sum=min (Sum+a[1]+a[0]+a[n-1]+a[1],sum+a[n-1]+a[0]+a[n-2]+a[0]);             n-=2;18         }19         if (n==3) sum+=a[0] +a[1]+a[2];20         Else if (n==2) sum+=a[1];21         else sum+=a[0];22         printf ("%d\n", sum);     }24}

6. Interval coverage Issues
POJ1328 is a classic problem of greedy calculation law. The main idea is to assume that the coastline is an infinitely extended line. Land on one side of the shoreline, while the ocean is on the other side. Every small island is a point on the ocean. The radar is located on the coastline and can only cover the d distance, so if the islets can be covered, the distance between them is D. The title requires the calculation of the minimum number of radars that can cover all the islands given. For each small island, we can calculate the interval of the location of a radar.

The problem turns into how to cover these intervals with as few points as possible. First, all the intervals are sorted by the left endpoint size, and a point is required at the beginning. If the two intervals intersect without overlap, we do not need to do anything; If an interval is completely contained in another interval, we need to update the right end of the interval, and if the two intervals do not intersect, we need to increase the point and update the right endpoint.
AC Code:

 1 #include <cmath> 2 #include <iostream> 3 #include <algorithm> 4 using namespace std; 5 struct point 6 {7 double X; 8 double y; 9}point[1000];10 one int cmp (const void *a, const void *b) Turn (* (point *) a) .x> (* (point *) b). x?1:-1;14}15, int main (), {$ int n,d;19 int num=1;20 while (cin>& GT;N&GT;&GT;D) {int counting=1;23 if (n==0&&d==0) break;24 for (int i=0;i<n;i++)                 + {x,y;27 int cin>>x>>y;28 if (y>d) 29 {30 Counting=-1;31}32 Double t=sqrt (d*d-y*y); 33//conversion to a minimum interval the problem of the POI NT[I].X=X-T;35//Interval left endpoint point[i].y=x+t;37//Interval Right endpoint}39 if (counting !=-1) (Qsort) (Point,n,sizeof (point[0]), CMP); 42//Sort by interval left endpoint double s=poin           T[0].Y;44//Zone right end 45  for (int i=1;i<n;i++) Point[i].x>s {if () 48//If two intervals are not coincident, increase the number of radars and update the right side                 Counting++;51 S=POINT[I].Y 52}53                     else if (point[i].y<s) 54//If the second interval is fully contained in the first interval, update the right endpoint 55 {56 s=point[i].y;57}58}59}60 cout<< "case" <<num<< ': ' << "' <<counting<<endl;61 num++;     62}63}

7. Sales competition
In the school OJ to do a better problem, here code a bit. Suppose there are even days, a requirement to buy an item every day or to sell an item, you can only select one operation and cannot choose, start without this item. Now give you the daily Item price list and ask to calculate the maximum benefit. The first thing to understand is that the first day must be bought, the last day must be sold, and the last hand no items. So apart from the first day and the last day we take two days each, small buy big sell, and put the price of selling into a minimum heap. If the price is larger than the top of the heap, swap. In this way we guarantee that the price of the sale is always greater than the price of the purchase, will be able to achieve maximum benefits.

 1 #include <queue> 2 #include <vector> 3 #include <cstdio> 4 #include <cstdlib> 5 #include < Cstring> 6 #include <iostream> 7 #include <algorithm> 8 using namespace std;      9 Long Long int price[100010],t,n,res;10 one int main () {Ios::sync_with_stdio (false); cin>>t;15 while (t--), {cin>>n;18 priority_queue<long long int, vector<long long int>, GR Eater<long long int> > q;19 res=0;20 for (int i=1;i<=n;i++) {CIN&GT;&G         t;price[i];23}24 res-=price[1];25 res+=price[n];26 for (int i=2;i<=n-1;i=i+2) 27             {A long long int buy=min (price[i],price[i+1]); a long long int sell=max (price[i],price[i+1]); 30                     if (!q.empty ()) + (Buy>q.top ()) 33 {34   Res=res-2*q.top () +buy+sell;35 q.pop (); 36                  Q.push (Buy); PNs Q.push (Sell);}39 Else40             {res=res-buy+sell;42 Q.push (sell); 43}44}45         Else46 {res=res-buy+sell;48 q.push (sell); 49}50 } Wuyi cout<<res<<endl;52}53}

Let's take a couple of examples with the knowledge of data structures.
8.Huffman encoding
This is also an example of the introduction to algorithms. Huffman encoding is a very effective encoding method widely used in data file compression. We can have a number of ways to represent the information in the file, if the 01 string representation of characters, using fixed-length encoding representation, you need 3 bits to represent a character, the entire file encoding needs 300,000 bits, a variable-length encoding, to the frequency of high characters shorter encoding, low-frequency characters longer encoding, To achieve the purpose of overall coding reduction, the entire file encoding needs (45X1+13X3+12X3+16X3+9X4+5X4) x1000=224000 bit, this shows that the variable length code is better than the fixed length code scheme, the total code length decreased by about 25%.

The code that specifies a 01 string for each character as its code, and that requires any one character, is not a prefix for other character codes, which are called prefix codes. It may be a better name, but the prefix code is a standard term that is uniformly recognized. The prefix nature of the encoding can make decoding very simple: for example, 001011101 can only be decomposed into 0,0,101,1101, so its decoding is aabe. Decoding process needs to easily remove the prefix of the code, for this can be used as a binary tree prefix code data structure: The leaf represents a given character; the path from the tree root to the leaf is used as the prefix code for the character, and 0 or 1 of each digit in the code is a signpost indicating a node to the left or right son.

As can be seen, the optimal prefix code of the two-tree is always a complete binary tree, while the fixed-length code of two tree is not a complete binary tree. A prefix code encoding scheme for a given coded character set C and frequency distribution f,c corresponds to a binary tree T. The depth of character C in the tree T is recorded as DT (c), and DT (c) is also the prefix code length of the character C. The average code length is defined as:

The prefix code coding scheme, which makes the average code up to the minimum, is called the optimal prefix code of c.
Huffman encoding method: first merge the minimum frequency of 2 characters corresponding subtree, calculate the frequency of the merged subtree, reorder the sub-tree, the sequence of sub-tree to merge, repeat the above process, all nodes are combined into 1 complete two-fork tree, the two-tree edge is given 0, 1, get the variable length encoding of each character.

The

POJ3253 is a typical example of using this idea. The main idea is to have an infinite length of the board saw a few pieces of a given length of small planks, each saw a certain cost, the cost is the length of the current sawn wood. The minimum cost is given for the length of the planks and the number of small planks for each requirement. In order to require 3 pieces of wood of the length of the 5,8,5, for example: sawing the length of 21 planks from an infinitely long plank, spending 21, and then sawing from a 21-length plank on a board of length 5, which costs 5, and a 16-length plank on a plank of length of the board, 8; Total cost =21+5+8=34. Using Huffman thought, to make the total cost of the smallest, then each time only select the minimum length of two pieces of wood added, and then add these and accumulated to the total cost. To improve efficiency, use priority queue optimization, and also note that you use a long long int to save the results.
AC Code:

1 #include <queue> 2 #include <cstdio> 3 #include <iostream> 4 using namespace std; 5  6 int main () 7 {8     long long int sum; 9     int i,n,t,a,b;10 while     (~scanf ("%d", &n)         Priority_queue<int,vector<int>,greater<int> >q;13 for         (i=0;i<n;i++),         {             scanf ("%d", &t),             Q.push (t),         }18         sum=0;19         if (q.size () ==1), {a=q.top ()             ; 22             sum+=a;23             q.pop ();         }25 while         (Q.size () >1)             (a=q.top); Q.pop ();             b=q.top ();             Q.pop ();             t=a+b;32             sum+=t;33             q.push (t);         }35         printf ("%lld \ n ", sum);     }37}

9.Dijkstra algorithm
The Dijkstra algorithm was proposed by E.w.dijkstra in 1959 and is currently recognized as the best method to solve the shortest path, with the condition that negative edges cannot exist in the graph. The algorithm solves the shortest path problem of a single source point to other vertices, and its main feature is that the next vertex selected at each iteration is the vertex closest to the source point outside the Mark Point, which is simply the idea of the bfs+ greedy algorithm.

 1 #include <iostream> 2 #include <algorithm> 3 #define INF 4 #define MAX_V 5 using namespace std; 6 7 int Main () 8 {9 int v,e;10 int i,j,m,n;11 int cost[max_v][max_v];12 int d[max_v];13 bool Used[m     Ax_v];14 cin>>v>>e;15 Fill (d,d+v+1,inf), Fill (used,used+v,false), + for (i=0;i<v;i++) 18         {j=0;j<v;j++) {i==j) cost[i][j]=0;22 else cost[i][j]=inf;23 }24}25 for (m=0;m<e;m++) (cin>>i>>j>>cost[i][j];28 cost[j][i]= cost[i][j];29}30 cin>>n;31 d[n]=0;32//Source point (True) @ {+ int v=v;36 f The OR (m=0;m<v;m++) Notoginseng (!used[m) && (D[m]<d[v]) v=m;39} V==V) break;41 used[v]=true;42 for (m=0;m<v;m++) [D[m]=min] ); 45}46}47     for (i=0;i<v;i++) cout<< "The shortest distance between" <<n<< "and" &LT;&LT;I&L t;< "is" <<d[i]<<endl;50}51}

10. Minimum spanning tree algorithm
A network is represented as undirected connected with a weighted graph G = (V, e), and the right of each edge (V,W) in E is c[v][w]. If the sub-figure g ' of G is a tree containing all the vertices of G, then G ' is the spanning tree of G. The cost of spanning a tree is the sum of the rights of each edge on the spanning tree, and in all spanning trees of G, the smallest spanning tree is called the minimum spanning tree of G. For example, when designing a communication network, the city is represented by the vertex of the graph, the weight of the Edge (V,W) C[v][w] represents the cost of establishing a communication line between the City V and the city W, and the minimum spanning tree gives the most economical solution to establish the communication network.

The Kruskal algorithm and the prim algorithm for constructing the minimum spanning tree utilize the MST (minimum Spanning Tree) property: Set the vertex set U is a true subset of V (can be arbitrarily selected), if (u,v) ∈e is the edge across the point set U and V-u, that is u∈u,v∈v-u, and on all such edges, (u,v) C[U][V] Minimum, there must be a minimum spanning tree of G, which takes (U,v) as one of the edges.

The use of the disprove method can be very simple to prove this nature. Assuming any of the minimum spanning tree t for G, for the point set U and V-u, (U,V) ∈e is the smallest weight across the 2-point set, T contains the least-weighted edge <u, V>, but t includes the nodes U and v. Adding <u,v> to the tree T, the tree T will become a sub-graph with a loop, and there is an edge <u ', V ' >,u ' ∈u,v ' ∈v-u that is different from <u,v> on the way back. The <u ', V ' > is deleted to get another tree T ', that is, the tree T ' is replaced by the side <u ', V ' > in T in the <u,v> get. Because the cost of these 2 sides satisfies c[u][v]≤c[u '][v ', so t ' consumes ≤t, which is inconsistent with the hypothesis that T is any minimum spanning tree, thus it can be proven.

Each step of the prim algorithm chooses to join the spanning tree with the least weighted edge of the connection U and v-u.

 1 #include <iostream> 2 #include <algorithm> 3 #define MAX_V 4 #define INF 5 using namespace std; 6 7 int Main () 8 {9 int v,e;10 int i,j,m,n;11 int cost[max_v][max_v];12 int mincost[max_v];13 bool U Sed[max_v];14 cin>>v>>e;15 Fill (mincost,mincost+v+1,inf), Fill (used,used+v,false), + for (i=0 ; i<v;i++) (j=0;j<v;j++) {(i==j) cost[i][j]=0;22 else cos T[i][j]=inf; }24}25 for (m=0;m<e;m++) (cin>>i>>j>>cost[i][j];28 cost[j ][i]=cost[i][j];29}30 mincost[0]=0;31 int res=0;32 while (true) $ {int v=v;35 for (m         =0;m<v;m++) (!used[m) ((mincost[m]<mincost[v)) (v=m;39)         } if (v==v) break;41 used[v]=true;42 res+=mincost[v];43 for (m=0;m<v;m++) 44 {45            Mincost[m]=min (Mincost[m],cost[v][m]); }47}48 cout<<res<<endl;49}

Each step of the Kruskal algorithm directly joins the generation tree with the least-weighted ring edge, and we can achieve it perfectly by using and checking the data structure.

 1 #include <iostream> 2 #include <algorithm> 3 #define MAX_E 4 using namespace std;     5 struct Edge 6 {7 int u,v,cost; 8};  9 int pre[max_e];10 Edge es[max_e];11 int Find (int x), initvalue (int x), bool Same (int x,int y), + void unite (int     X,int y); 21 bool Comp (const edge& e1,const edge& E2), + int main (), {int v,e;20 int i,j,m,n; Cin>>v>>e;22 InitValue (V); Max for (i=0;i<e;i++) cin>>es[i].u>>es[i].v>>es[i].cost        ; (Es,es+e,comp), and int res=0;26 for (i=0;i<e;i++), {The Edge e=es[i];29 if (!same (E . u,e.v)) (Unite (E.U,E.V); res+=e.cost;33}34}35 cout<<res&lt    ;<endl;    }37 + bool Comp (const edge& e1,const edge& E2)-(+)-e1.cost<e2.cost; }42 initvalue (int x)}47 {(int i=0;i<x;i++) pre[i]=i;46, int x) (int ×) r=x, pre[r]!=r r=pre[r];52 int i=x,j;53 while (pre[i]!=r), j=pre[i];56 pre[i]=r;     i=j;58}59 return r;60}61, bool Same (int x,int y), (Find (x) ==find (y)) return true;65    else return false;    }67-Unite (int x,int y), {x-int fx=find (×), Int. int Fy=find (y), and if (fx!=fy) pre[fx]=fy; 73}

The basic knowledge of the greedy algorithm is briefly introduced here, hoping that we can continue to study in depth as a basis.

0 Basic Greedy algorithm

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.