Advanced Guide to algorithm competition

Just write down the greedy questions in the book.

color a tree

Title Description:
                    <p>A tree has n nodes. These nodes are labeled as: 1,2,3 & hellip; n. each node i has a weight A[i]. </p>

Now we need to dye all the nodes of this tree. The dyeing rules are:

The root node R can be colored at any time; for other nodes, its parent node must be colored before being colored.

The cost of each dyeing is T*A[i], where T represents the current dyeing times.

Find the minimum total cost of coloring this tree.

Input format

The first row contains two integers, n and R, representing the number of nodes in the tree and the serial number of the root node.

The second line contains n integers, representing the weights of all nodes. The ith number is the weight A[i] of the ith node.

Next n-1 lines, each line contains two integers a and b, representing the sequence number of two nodes. The two nodes satisfy the relationship: a node is the parent node of b node.

The parent nodes and themselves of n-1 nodes other than the root node are represented in this n-1 row.

The numbers in the same row are separated by spaces.

Output format

Output an integer representing the minimum total cost of coloring the tree.

Data range

1 <= n <= 1000,
1 <= A[i] <= 1000

Input example:

5 1
1 2 1 2 4
1 2
1 3
2 4
3 5

Output example:

33
Code:
#include<bits/stdc++.h>
using namespace std;
struct nodes{
	int fa,sum,size;//fs stores the number of the parent node, sum stores the sum of the number of merges of this node, and size stores the number of merges
	double avr;//Store the average weight after merging
};
nodes p[1010];
int n,root;
long long ans=0;//Save answers

int find()//Used to find the point with the largest average weight in each cycle
{
	int res=0;//Set the initial value to 0 first
	double minn=0;//
	for(int i=1;i<=n;i++)
	{
		if(i!=root&&p[i].avr>minn)//Find the largest one except the root node. Because the root node does not have a parent node, it cannot find the root node (but the root node can be regarded as a parent node by others to participate in the calculation)
		{
			minn=p[i].avr;//
			res=i;//
		}
	}
	return res;//
}


int main()
{
	cin>>n>>root;
	for(int i=1;i<=n;i++)
	{
		cin>>p[i].avr;//The number entered for the first time is the average
		p[i].sum=p[i].avr;
		p[i].size=1;//Initial value is 1
		ans+=p[i].sum;//Since each number is a separate number at the beginning, it should be accumulated first
	}
	for(int i=1;i<=n-1;i++)
	{
		int x,y;
		cin>>x>>y;
		p[y].fa=x;//Storage
	}
	for(int i=1;i<=n-1;i++)
	{
		int ver=find();//Find the point with the maximum average weight
		int f=p[ver].fa;//Find the parent node of this point
		ans+=p[ver].sum*p[f].size;//Update the answer, and put the value of ver node after the value of other node
		p[ver].avr=-1;//Assign the average value of the ver node to a negative number, indicating that it has been selected.
		for(int j=1;j<=n;j++)
			if(p[j].fa==ver)
			p[j].fa=f;//Reassign all children of the ver node to the parent of the ver
		p[f].sum+=p[ver].sum;//Update parent
		p[f].size+=p[ver].size;//
		p[f].avr=(double)p[f].sum*1.0/p[f].size;//
		
	}
	cout<<ans;
	return 0;
}
Analysis:

This question is a bit like a collection. The mathematical proof of this problem is really a little difficult for me, a waste of mathematics.
According to the requirements of the topic, if you want to dye a point, you must dye its parent node first. And how do we know which number to dye? In fact, it depends on whether the weight of this number is the largest. Generally speaking, the one with the largest weight should be colored first, but because of the limitation, the parent node should be colored first, and then the child node should be colored immediately (these two points are regarded as a whole).
However, if so, there is no way to determine which parent node to dye before dyeing (for example, if the parent node is very small and the sibling node with a parent node is very large). So here's a mathematical proof:

Then there is the question of how to accumulate the answers, because this is a little bit of processing, and the answers are updated little by little. When the current post relationship changes, the answers will also change.
In fact, the whole process is to merge one point at a time, but each time the point (Group) with the largest average weight is merged with its parent node, and each time it is merged, it should be placed behind the parent node, but because the ordinal number has changed, it needs to use the number of elements already merged in the parent node * the total number of child nodes (this is easier to prove that I will not write).
Or write:
Suppose there are two groups of numbers: b1 ~ bn and a1 ~ am.
b array needs to be placed before a array.
ans=b1+2b2...+nbn+(n+1)a1+...(n+m)am;
Because a array has been accumulated before, but at that time a array is sorted from 1. So if we want to add up, we need to add n (a1 + +am).

Then there are some details to deal with, see the code comments.

King game:

Title Description:
                    <p>On the national day of H, the king invited n ministers to play a game with prizes. </p>

First, he asked each minister to write down an integer on his left and right hand respectively, and the king himself wrote an integer on his left and right hand.

Then, let the n ministers line up, with the king at the front of the line.

After queuing up, all ministers will receive gold coins from the king. The gold coins each Minister receives are:

The product of the number on the left hand of all the people in front of the minister divided by the number on his right hand, and then rounded down.

The king doesn't want a minister to get a lot of awards, so he wants you to rearrange the order of his team so that the minister who gets the most awards can get as little as possible.

Note that the king is always at the front of the line.

Input format

The first line contains an integer n indicating the number of ministers.

The second line contains two integers a and b, separated by a space, representing the integers on the king's left hand and right hand, respectively.

Next n lines, each line contains two integers a and b, separated by a space, representing the integers on each minister's left hand and right hand respectively.

Output format

The output has only one line, including an integer, indicating the number of gold coins obtained by the most rewarded minister in the rearranged team.

Data range

1 <= n <= 1000
0< a,b <10000

Input example:

3
1 1
2 3
7 4
4 6

Output example:

2
Code:
#include<bits/stdc++.h>
using namespace std;
int n;
int k_a,k_b;
struct mnst
{
    int l,r;
}p[1009];
vector<int >maxx;   
bool com(mnst x,mnst y)
{
    return x.l*x.r<y.l*y.r;//Sorting ratio size
}
vector<int > mul(vector<int > a,int b)
{
    vector<int >c;
    int t=0;
    for(int i=0;i<a.size();i++)
    {
        t+=a[i]*b;
        c.push_back(t%10);
        t/=10;
    }
    while(t) c.push_back(t%10),t/=10;
    return c;
}//High precision multiplication
vector<int > div(vector<int > a,int b)
{
    vector<int >c;
    int t=0;
    bool is_first=0;
    for(int i=a.size() -1 ;i >= 0 ;--i)
    {
        t=t*10+a[i];
        int x=t/b;
        if(x||is_first)
        {
            is_first=1;
            c.push_back(x);
        }
        t%=b;
    }
    return vector<int >(c.rbegin(),c.rend());
} //High precision Division
vector<int > max_vec(vector<int > a,vector<int > b)
{
    if(a.size()>b.size()) return a;
    if(a.size()<b.size()) return b;
    if(vector<int >(a.rbegin(),a.rend())>vector<int >(b.rbegin(),b.rend()))
    return a;
    return b;
}//Comparative size
void output()
{
    for(int i=maxx.size()-1;i>=0;--i)
        cout<<maxx[i];
    cout<<endl; 
}//output
int main()
{
    cin>>n;
    cin>>k_a>>k_b;
    for(int i=1;i<=n;i++)
    {
        cin>>p[i].l>>p[i].r;
    }
    sort (p+1,p+n+1,com);
    vector<int >sum;
    sum.push_back(1);
    sum=mul(sum,k_a);

    for(int i=1;i<=n;i++)
    {
        maxx=max_vec( div(sum,p[i].r) ,maxx);
        sum=mul(sum,p[i].l);    
    }
    output();
    return 0;
}

This problem mainly involves the proof of greed, which can be proved by comparing the size of adjacent term exchange (the proof process is omitted here)
And then there's the high-precision algorithm

There's another question

Acrobatic ox:

                    <p>Farmer John's N cows (No. 1..N) plan to escape and join the circus, so they decide to practice acrobatics. </p>

The cows are not very creative. They only put forward an acrobatic performance:

During the performance, the cows stand on each other to form a high vertical stack.

Cows are trying to find the order in which they should be on this stack.

Each of these N cows has its own weight of $W_i $and its own strength of $S_i $.

The probability that a cow can't support depends on the total weight of all the cows on its head (excluding itself) minus the value of its physical strength. Now it is called the risk value. The greater the risk value, the higher the probability that the cow can't support.

Your task is to prioritize the cows so that the maximum of the risk values for all cows is as small as possible.

Input format

Enter the integer N in the first line to indicate the number of cows.

Next N lines, enter two integers for each line, representing the weight and strength of the cow, and the I line represents the weight of the I cow $W_i $and its strength $S_i $.

Output format

Output an integer representing the minimum possible value of the maximum risk value.

Data range

$1 \le N \le 50000$,
$1 \le W_i \le 10,000$,
$1 \le S_i \le 1,000,000,000$

Input example:

3
10 3
2 5
3 3

Output example:

2
#include<bits/stdc++.h>
using namespace std;
typedef pair<int ,int > PLL;
PLL cow[50010];
bool com(PLL a,PLL b)
{
    return a.first + a.second < b.first + b.second;
}
int main()
{
    int n;
    cin>>n;
    for(int i = 1;i <= n;i++)
    {
        cin>>cow[i].first>>cow[i].second;
    }
    sort(cow + 1,cow + n + 1,com);
    int maxx = -99999999;
    int sum=0;
    for(int i = 1;i <= n;i++)
    {
        maxx = max(maxx , sum - cow[i].second);
        sum += cow[i].first;
    }
    cout<<maxx;
    return 0;
}

Then there are three bipartite graphs

Sunscreen

                   <p>There are C cows for sunbathing, and the I cows need sunshine between minSPF[i] and maxSPF[i] unit intensity. </p>

Each cow must apply sunscreen before sunbathing. There are L kinds of sunscreen. After applying the I kind of sunscreen, the sunlight intensity received by the body will stabilize to SPF[i], and the I kind of sunscreen has a cover[i] bottle.

Ask how many cows can be sunbathed at most.

Input format

Enter the integers C and L on the first line.

In the next line C, input the minSPF and maxSPF values of a cow in order, that is, input minSPF[i] and maxSPF[i] in line I.

In the next L line, input the SPF and cover values of a sunscreen in order, that is, input SPF[i] and cover[i] in line I.

The data in each row is separated by spaces.

Output format

Output an integer representing the maximum number of cows that can be sunbathed.

Data range

$1 \le C,L \le 2500$,
$1 \le minSPF \le maxSPF \le 1000$,
$1 \le SPF \le 1000$

Input example:

3 2
3 10
2 5
1 5
6 2
4 1

Output example:

2

This problem seems to use the Hungarian algorithm:
See the link for details of the algorithm, which is quite complete
Bipartite graph + Hungarian algorithm

#include<bits/stdc++.h>
using namespace std;
struct cow{
	int sl,bg;
};
cow a[2509];
struct fss{
	int s,cover;
};
fss b[2509];
bool com(cow x,cow y)
{
	return x.sl<y.sl;
}
bool cm(fss x,fss y)
{
	return x.s<y.s;
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d%d",&a[i].sl,&a[i].bg);
	for(int i=1;i<=m;i++)
		scanf("%d%d",&b[i].s,&b[i].cover);
	sort(a+1,a+n+1,com);
	sort(b+1,b+m+1,cm);
	int ans=0;
	for(int j=n;j>=1;--j)
	{
//		cout<<j<<endl;
		for(int i=m;b[i].s>=a[j].sl;--i)
		{
			if(b[i].s>=a[j].sl&&b[i].s<=a[j].bg&&b[i].cover>0)
			{
				b[i].cover--;
				ans++;
				break;
			}
		}
	}
	cout<<ans;
	return 0;
}

Radar:

                    <p>Suppose the coast is an infinite straight line, with land on one side of the coast and the ocean on the other. </p>

Each island is located at a point on the side of the ocean.

All radar devices are located on the coastline, and the radar monitoring range is d. when the distance between the island and a radar does not exceed D, the island can be covered by radar.

We use the Cartesian coordinate system to define the coastline as the x-axis, with one side of the sea above the x-axis and the other side of the land below the x-axis.

Now, the specific coordinates of each island and the detection range of radar are given. Please find the minimum number of radars required to make all islands covered by radar.

Input format

In the first line, two integers n and d are input, representing the number of islands and the radar detection range respectively.

Next n lines, each line input two integers, respectively representing the island's x, y axis coordinates.

The same row of data is separated by spaces.

Output format

Output an integer representing the minimum number of radars required, and output "- 1" if there is no solution.

Data range

$1 \le n \le 1000$

Input example:

3 2
1 2
-3 1
2 1

Output example:

2
#include<bits/stdc++.h>
using namespace std;
struct island{
double s,e;
};
island a[1010];
int n;
int d;
int ans;
const double eps=1e-6;
void change(double x,double y,int number)
{
	double dx=sqrt(d * d - y * y);
	a[number].s = x - dx;
	a[number].e = x + dx;
}
bool com(island x,island y)
{
	return x.e<y.e;
}
int main()
{
	scanf("%d%d",&n,&d);
	double x,y;
	for(int i=1;i<=n;i++)
	{
		scanf("%lf%lf",&x,&y);
		if(y>d)
		{
			cout<<-1;return 0;
		}
		change(x,y,i); 
	}
	sort(a+1,a+n+1,com);
	double now=-1e10;
	for(int i=1;i<=n;i++)
	{
		if(now + eps < a[i].s)
		{
			ans++;
			now = a[i].e;
		}
	}
	cout<<ans<<endl;
	return 0;
}

Tasks:

                    <p>Today, a company has M tasks to complete. </p>

Each task has the corresponding difficulty level and the time required to complete the task.

The difficulty level of the ith task is $y_i $, and the time required to complete the task is x_i $minutes.

If the company completes this task, they will receive $500 * $x_i $+ 2 * $y_i $).

The company has N machines, each with the longest working time and level.

If the task takes longer than the maximum working time of the machine, the machine cannot complete the task.

If the difficulty level of the task exceeds the level of the machine, the machine cannot complete the secondary task.

Each machine can only complete one task in a day.

Each task can only be performed by one machine.

Please design a task allocation plan for them so that the company can maximize the number of tasks they can complete today.

If there are multiple solutions, they want to choose the one that makes the most money.

Input format

The input contains several test cases.

For each test case, the first line contains two integers, N and M, representing the number of machines and tasks, respectively.

Next N lines, each containing two integers $x_i,y_i $, represent the maximum machine working time and machine level respectively.

Then row M, each of which contains two integers $x_i,y_i $, respectively representing the time required to complete the task and the difficulty level of the task.

Output format

For each test case, output two integers, representing the maximum number of tasks that the company can complete today and the revenue they will get.

Data range

$1 \le N,M \le 100000$,
$0 < x_i < 1440$,
$0 \le y_i \le 100$

Input example:

1 2
100 3
100 2
100 1

Output example:

1 50004
#include<bits/stdc++.h>
using namespace std;
typedef pair<int ,int > PLL;
PLL op[100010],task[100010];  
int n,m;
int main()
{
	 while(cin>>n>>m)
    {
        for(int i=1;i<=n;i++)
           cin>>op[i].first>>op[i].second;
        for(int i=1;i<=m;i++)
            cin>>task[i].first>>task[i].second;
        sort(op+1,op+n+1);
        sort(task+1,task+m+1);
        multiset<int >ys;
       unsigned long long ans=0,res=0;
        for(int i=m,j=n;i>=1;--i)
        {
            while(op[j].first>=task[i].first&&j>=1) ys.insert(op[j--].second);
            auto x=ys.lower_bound(task[i].second);
            if(x!=ys.end())
            {
                ans++;
                res+=task[i].first*500+task[i].second*2;
                ys.erase(x);
            }
        }
        cout<<ans<<" "<<res<<endl; 
    }
    
    return 0;
}

Livestock Reservation:

Title Description
This is a simple greedy problem, but one thing is to use a small root heap to store the last time of each cattle pen without overtime.
Code:

#include<bits/stdc++.h>
using namespace std;
priority_queue<pair<int ,int>,vector<pair<int,int > > ,greater<pair<int,int > > >q;
struct cow{
	int s,e,l,number;
};
cow a[50009];
bool com(cow x,cow y)
{
	return x.s<y.s;
}
bool com2(cow x,cow y)
{
	return x.number<y.number;
}
int n;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i].s,&a[i].e);
		a[i].number=i;
	}
		
	sort(a+1,a+n+1,com);
	int count=0;
	for(int i=1;i<=n;i++)
	{
		if(!q.empty()&&a[i].s>q.top().first)
		{
			int num=q.top().second;
			q.pop();
			q.push(make_pair(a[i].e,num));
			a[i].l=num;
		}
		else
		{
			q.push(make_pair(a[i].e,++count));
			a[i].l=count;
		}
	}
	sort(a+1,a+n+1,com2);
	cout<<count<<endl;
	for(int i=1;i<=n;i++)
	{
		printf("%d\n",a[i].l);
	}
}

in general:

Greed can be divided into the following categories:
1. Prove the sorting method by calculation.
2. By analyzing the maximum matching problem of bipartite graph (Hungarian algorithm without augmented path) or other problems related to graph theory.
3. Simple thinking.

Published 9 original articles, won praise 7, visited 140
Private letter follow

Posted by FlashbackJon on Wed, 29 Jan 2020 01:50:35 -0800