Finding an arrangement that yield minimum salary - algorithm

Once again I am stuck with a sopj problem pilots
The problem statement is..
Charlie acquired airline transport company and to stay in business he needs to lower the expenses by any means possible. There are N pilots working for his company (N is even) and N/2 plane crews needs to be made. A plane crew consists of two pilots - a captain and his assistant. A captain must be older than his assistant. Each pilot has a contract granting him two possible salaries - one as a captain and the other as an assistant. A captain's salary is larger than assistant's for the same pilot. However, it is possible that an assistant has larger salary than his captain. Write a program that will compute the minimal amount of money Charlie needs to give for the pilots' salaries if he decides to spend some time to make the optimal (i.e. the cheapest) arrangement of pilots in crews.
input
The first line of input contains integer N, 2 ≤ N ≤ 10,000, N is even, the number of pilots working for the Charlie's company. The next N lines of input contain pilots' salaries. The lines are sorted by pilot's age, the salaries of the youngest pilot are given the first. Each of those N lines contains two integers separated by a space character, X i Y, 1 ≤ Y < X ≤ 100,000, a salary as a captain (X) and a salary as an assistant (Y).
output
The first and only line of output should contain the minimal amount of money Charlie needs to give for the pilots' salaries.
sample
input
4
5000 3000
6000 2000
8000 1000
9000 6000
output
19000
input
6
10000 7000
9000 3000
6000 4000
5000 1000
9000 3000
8000 6000
output
32000
Now i am using a greedy approch as it is clear that first pilot should be assistant and after that i check if it will be possible to save money by making the pilot captain if yes then i will make him a captain else an assistant.
It is perfectly working for most of the cases but I get a wrong awnser.
my code is..
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define FOR(i,n) for(int i=0;i<n;i++)
int main()
{
int n;
//freopen("input.txt","r",stdin);
cin>>n;
vector<pair<pii,int> > data;
FOR(i,n)
{
int csal,asal;
cin>>csal>>asal;
int diff=csal-asal;
data.pb(mp(mp(csal,asal),diff));
}
int ccount=0,acount=0,sal=0;
FOR(i,n)
{
if(acount<n/2)
{
int flag=1;
for(int j=i+1;j<=i+(acount-ccount);j++)
{
if(data[i].se<=data[j].se)
{
//cout<<j<<" ";
flag=0;
break;
}
}
if(flag)
{
sal+=data[i].fi.se;
acount++;
}
else
{
sal+=data[i].fi.fi;
ccount++;
}
}
else
{
sal+=data[i].fi.fi;
ccount++;
}
//cout<<sal<<" "<<i<<"\n";
}
cout<<sal<<"\n";
return 0;
}
please help me to solve this problem..

Here is a solution with O(N log N) running time. It uses greedy algorithm, but it is different from yours.
1)Let's assume that delta[i] = X[i] - Y[i].
2)Now let's process pilots sorted by delta[i] in descending order. We will assume that all pilots are initially given captain positions.
3)Each pilot should be reassigned to assistant position if it is possible.
That's it. I claim that this algorithm always gives a correct result.
Proof:
1)When a pilot cannot be given an assistant job?
i)When there are no "free" captains to the right(in terms of age) of him(that is, if the number of captains to the right of him is greater than or equal to the number of assistants). Why could this happen? Only if there are "too many" assistants to the right of him. Let's assume that we decided to fix it. It would require changing one of the assistants to the captain. But if a pilot is an assistant, he was processed before the current pilot. It means that his delta is greater(recall that we iterate over them in sorted order). One more observation: one assistant can block only one captain(because the crew includes only one captain). These two observation show that changing something when it is not possible to make current pilot an assistant would only make the answer worse.
ii)When he is taken as a captain by an assistant to the left(in terms of age) from him. To fix it, it would be necessary to make that guy a captain again, like in i). It would make the answer only worse(the proof is the same as in the situation above).
2)Using mathematical induction and two observations above, it can be proven rigorously that this algorithm is correct.
3)This algorithm will always produce exactly N / 2 assistants because it makes a pilot an assistant whenever possible and there are exactly N / 2 possibilities to do it.
The only question remaining is: how to check if it is possible to make the current pilot an assistant?
Here is a fast way: let's assign each pilot 1 if he is a captain and -1 otherwise. Let's take a look at this array of -1 and 1 in order of pilots' ages. I claim that if there is a suffix with negative sum, the configuration is invalid. Otherwise, it is valid(this statement is not that hard to prove, but I will not post the proof here or there will too much proofs in my answer). So we need to maintain two operations: change -1 to 1(and vice versa) and tell if there is a suffix with negative sum. It is a standard problem and can be solved with segment tree(you can store total sum and minimum suffix sum in each node, update is easy because the value of only one element is changed at a time(that is, a value in a leaf)).
The complexity is O(N log N) because we need to sort the array and during the iteration at most 3 queries to a segment tree are done per one step(and each query takes O(log N) time).

Related

An algorithm to calculate foreign residence without enumerating days?

The visa conditions for a country to which I travel frequently include this restriction:
"You may reside in [country] for a maximum of 90 days in any period of 180"
Given a tentative list of pairs of dates (entry and exit dates), is there an algorithm that can tell me, for each visit, whether I will be in or out of compliance, and by how many days?
Clearly, one way to do this would be to build a large array of individual days and then slide a 180-day window along it, counting residence days. But I'm wondering whether there is a more elegant method which doesn't involve building a great long list of days.
The normal algorithm for this is basically a greedy algorithm, though it could also be seen as a 1D dynamic progamming algorithm. Basically, rather than sliding the window 1 day at a time, you slide it 1 starting-date at a time. Like so:
first_interval = 0
last_interval = 0
for first_interval = 0 to N:
# include more intervals as long as they (partially) fit within 180 days after the first one
while last_interval < N and A[last_interval].start - A[first_interval].start < 180:
last_interval += 1
calculate total number of days in intervals, possibly clipping the last one
The need to clip the last interval makes it a bit less elegant than it could otherwise be: in similar algorithms, rather than summing the total each time, you add to it for added-on intervals (when incrementing last_interval) and subtract from it for left-behind intervals (when incrementing first_interval). You could do something kind of similar here with the second-to-last interval, but unless you're in a serious performance bind it's probably best not to.
The following C++ code calculates the duration between two arbitrary dates no earlier than Jan 1, 1 A.D. in O(1) time. Is this what you're looking for?
#include <iostream>
using namespace std;
int days(int y,int m,int d){
int i,s,n[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
y+=(m-1)/12; m=(m-1)%12+1; if(m<1) {y--; m+=12;}
y--; s=y*365+y/4-y/100+y/400; y++;
if(y%4==0 && y%100 || y%400==0) n[2]++;
for(i=1;i<m;i++) s+=n[i]; s+=d; return s;
}
int main(){
cout<<days(2017,8,14)-days(2005,2,28)<<endl;
return 0;
}
You can use the days() function to map all dates of entry and exit to integers and then use the Sneftel's algorithm.

How do I solve this dynamic programming?

I am practising DP and I came across this question. http://www.spoj.com/problems/MPILOT/en/
Charlie acquired airline transport company and to stay in business he needs to lower the expenses by any means possible. There are N pilots working for his company (N is even) and N/2 plane crews needs to be made. A plane crew consists of two pilots - a captain and his assistant. A captain must be older than his assistant. Each pilot has a contract granting him two possible salaries - one as a captain and the other as an assistant. A captain's salary is larger than assistant's for the same pilot. However, it is possible that an assistant has larger salary than his captain. Write a program that will compute the minimal amount of money Charlie needs to give for the pilots' salaries if he decides to spend some time to make the optimal (i.e. the cheapest) arrangement of pilots in crews.
Input
The first line of input contains integer N, 2 ≤ N ≤ 10,000, N is even, the number of pilots working for the Charlie's company. The next N lines of input contain pilots' salaries. The lines are sorted by pilot's age, the salaries of the youngest pilot are given the first. Each of those N lines contains two integers separated by a space character, X i Y, 1 ≤ Y < X ≤ 100,000, a salary as a captain (X) and a salary as an assistant (Y).
Output
The first and only line of output should contain the minimal amount of money Charlie needs to give for the pilots' salaries.
After research, I found out this will be solved by DP but how exactly do I solve this? I have spent hours reading up on the links but I didn't get one which is easily understandable. Please help me.
There's actually a nice way to visualize it. Starting from the bottom left, the start of our ascending list, we can envision choosing a Y (assistant's salary) as a movement to the right and an X (captain's salary) as a movement up, with the condition that the southwest-northeast diagonal is not crossed (see Catalan Number in Wikipedia).
From this we can see that each node in the triangle has at most two predecessors, from the west or from the south, and so the bottom-up general case ought to be:
captain assistant
dp[i][j] = min(x[i+j-1] + dp[i-1][j], y[i+j-1] + dp[i][j-1])
Example:
x = [4,5,6,7]
y = [3,2,1,2]
[9+7]
[3+5] [min(8+1,5+6)]
[.] [3] [3+2]
I'll leave coding as an exercise.
As usual, we need to find a compact set of subproblems. Remembering the details of how the pilots are matched won't do -- we need something like the following characterization.
Consider a labeling that makes each pilot a captain or an assistant without regard to matching. There exists a valid matching if and only if the following two conditions hold:
There are N/2 captains and N/2 assistants.
For every age cutoff, there are at least as many assistants who are younger than the cutoff as there are captains who are younger than the cutoff.
The "only if" direction is easy: Condition 1 is obvious, and Condition 2 holds because the inequality holds for each 2-pilot crew, and we can sum the inequalities.
For the "if" direction, we actually have to construct crews. We proceed by induction. If there are no pilots, then the empty match is valid. Otherwise, since the youngest pilot is an assistant (by Condition 2) and there exists at least one captain (by Condition 1), there exists (by Sperner's lemma if you want to get fancy) a pair of pilots such that (a) no pilots are intermediate in age (b) the younger of the pair is an assistant (c) the older of the pair is a captain. Match the pair and remove them from the pool. Observe that both Conditions still hold, so match the rest by inductive hypothesis.
This observation leads to an O(N^2)-time dynamic program. We repeatedly read the salaries of the next oldest pilot and then compute, given that K pilots have been considered so far, for all C from 0 to [K/2], the minimum cost of paying K - C assistants and C captains among these pilots. At the end, return the cost of paying N/2 assistants and N/2 captains. Untested Python:
def cost(pilots):
cost = [0]
for i, (assistant_salary, captain_salary) in enumerate(pilots):
cost.append(float('inf')) # two-way sentinel
cost = [min(cost[c] + assistant_salary,
cost[c - 1] + captain_salary)
for c in range((i + 1) / 2 + 1)]
return cost[-1] # i.e., N/2
Let's formulate some conditions for a recursion: if we've reached the end, return the sum; if we have N/2 assistants, add a captain next; if we have the same number of assistants as captains left, add an assistant next (we can't have a captain younger than an assistant); otherwise, return the minimum cost of either adding a captain or an assistant.
JavaScript code:
var x = [4,5,6,7];
var y = [3,2,1,2];
var n = x.length;
function f(i,ys,s){
if (i == n){
return s;
}
if (ys == n / 2){
return f(i + 1,ys,s + x[i]);
} else if (i % 2 == 0 && ys == i / 2){
return f(i + 1,ys + 1,s + y[i]);
} else {
return Math.min(f(i + 1,ys + 1,s + y[i]),f(i + 1,ys,s + x[i]));
}
}
Output:
console.log(f(0,0,0)) // 16
For recursive approach in c++, you can follow this code for better understanding:
int min_salary(int a[],int n,int x,int c[])
{
if(n==0)
return 0;
if(x==0)
return(a[0]+min_salary(a+1,n-1,1,c+1));
if(x==n)
return(c[0]+min_salary(a+1,n-1,x-1,c+1));
else
return(min(a[0]+min_salary(a+1,n-1,x+1,c+1),c[0]+min_salary(a+1,n-1,x-1,c+1)));
}

How to improve this Dynamic programming solution(Optimisation in algorithm)

The Problem statement:
Assurance Company of Moving (ACM) is a company of moving things for people. Recently, some schools want to move their computers to another place. So they ask ACM to help them. One school reserves K trucks for moving, and it has N computers to move. In order not to waste the trucks, the school ask ACM to use all the trucks. That is to say, there must be some computers in each truck, and there are no empty trucks. ACM wants to know how many partition shemes exists with moving N computers by K trucks, the ACM ask you to compute the number of different shemes with given N and K. You needn't care with the order. For example N=7,K=3, the the following 3 partition instances are regarded as the same one and should be counted as one sheme: "1 1 5","1 5 1","5 1 1". Each truck can carry almost unlimited computers!!
Save Time :
You have to count how many sequences a[1..k] exist such that :
1) a[i] + a[2] + .... + a[k] = N such that permutations dont matter
My O(N*K^2) solution (Cannot figure out how to improve on it)
#include<assert.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
int DP[5001][5001];
void ini()
{
int i,j,k;
DP[0][0]=1;
for(k=1;k<=500;k++)
for(j=1;j<=500;j++)
for(i=1;i<=500;i++)
{
DP[i][j]+=j>=k?DP[i-1][j-k]:0;
DP[i][j]%=1988;
}
return ;
}
int main()
{
ini();
int N,K,i,j;
while(1)
{
scanf("%d%d",&N,&K);
if(N==0 && K==0)
return 0;
int i;
if(DP[K][N]==0)
{assert(0);}
printf("%d\n",DP[K][N]);
}
return 0;
}
Explanation of my solution DP[i][j] represents the number of ways I can have total j computers using i Trucks only.
The k represents the number of computers with which I am dealing with that means I am just avoiding permutations!
How can I improve it to O(N*K)?
Problem constraints
N (1<=N<=5000) and K(1<=K<=N)
Problem Link: Problem Spoj
Just say that you have K gift boxes and N chocolates.
I will start with a recursive and real easy to convert it to iterative solution.
The key to avoid repetitions is distributing chocolates in a ascending order (descending also works). So you 7 chocolates and I put 2 chocolate in the first box, I will put at least 2 in the second box. WHY? this helps in avoiding repetitions.
now onwards TCL = totalChocholatesLeft & TBL = totalBinsLeft
So S(TCL,TBL) = S(TCL-TBL,TBL) + S(TCL,TBL-1);
you have to call the above expression starting with S(n-k), k)
Why? because all boxes need at least one item so first put `1` each box.
Now you are left with only `n-k` chocolates.
That's all! that's the DP recursion.
How does it work?
So in order to remove repetitions we are maintaning the ascending order.
What is the easiest way to maintain the ascending order ?
If you put 1 chocolate in the ith box, put 1 in all boxes in front of it i+1, i++2 .....k.
So after keeping chocolate in a gift box, you have two choices :
Either you want to continue with current box :
S(TCL-TBL,TBL) covers this
or to move the next box just never consider this box again
S(TCL,TBL-1) covers this.
Equivalent DP would make have TC : O(NK)
This problem is equivalent to placing n-k identical balls (after already placing one ball in each cell to make sure it's not empty) in k identical cells.
This can be solved using the recurrence formula:
D(n,0) = 0 n > 0
D(n,k) = 0 n < 0
D(n,1) = 1 n >= 0
D(n,k) = D(n,k-1) + D(n-k,k)
Explanation:
Stop clauses:
D(n,0) - no way to put n>0 balls in 0 cells
D(n<0,k) - no way to put negative number of balls in k cells
D(n,1) - one way to put n balls in 1 cell: all in this cell
Recurrence:
We have two choices.
We either have one (or more) empty cell, so we recurse with the same problem, and one less cell: D(n,k-1)
Otherwise, we have no empty cells, so we put one ball in each cell, recurse with the same number of cells and k less balls, D(n-k,k)
The two possibilities are of disjoint sets, so the union of both sets is the summation of the two sizes, thus D(n,k) = D(n,k-1) + D(n-k,k)
The above recursive formula is easy to compute in O(1) (assuming O(1) arithmetics), if the "lower" problems are known, and the DP solution needs to fill a table of size (n+1)*(k+1), so this solution is O(nk)

How to find the minimum value of M?

I'm trying to solve this problem:
You have N relatives. You will talk to ith relative for exactly Ti
minutes. Each minute costs you 1 dollar . After the conversation,
they will add a recharge of Xi dollars in your mobile. Initially, you
have M dollars balance in your mobile phone.
Find the minimum value of M, that you must have initially, in your
phone, so that you don't run out of balance during any of the call
(encounter negative balance).
Note : You can call relatives in any order. Each relative will be
called exactly once.
Input:
N
T1 X1
T2 X2
2
1 1
2 1
Output:
2
This looks easy to me at first but I'm not able to find the exact solution.
My Initial thoughts:
We have no problem where Xi > Ti as it will not reduce our initial
balance. We need to take care of situation where where we will run
into loss i.e Ti > Xi.
But I am unable to make expression which will result in minimum
initial value.
Need guidance in approaching this problem to find optimal solution.
UPDATE:-
Binary Search approach seems to lead to wrong result (as proved by the
test case provided in the comment below by user greybeard.
So, this is another approach.We maintain the difference between call cost
and recharge amount.
Then we maintain two arrays/vectors.
If our recharge amount is strictly greater than cost of call, we put
the call in the first array ,else we put it in the second array.
Then we can sort the first array according to the cost and the second array
according to the recharge amount. We then update the diff by adding the
least amount of recharge from the call where our cost is greater than recharge
Then we can iterate through our first array and update our max
requirement,requirement for each call and current balance.Finally, our answer
will be the maximum between max requirement and the diff we have maintained.
Example :-
N = 2
T1 = 1 R1 = 1
T2 = 2 R2 = 1
Our first array contains nothing as all the calls have cost greater than
or equal to recharge amount. So, we place both calls in our second array
The diff gets updated to 2 before we sort the array. Then, we add the min
recharge we can get from the calls to our diff(i.e 1).Now, the diff stands
at 3.Then as our first array contains no elements, our answer is equal to
the diff i.e 3.
Time Complexity :- O(nlogn)
Working Example:-
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100007
int n,diff;
vector<pair<int,int> > v1,v2;
int main(){
diff = 0;
cin>>n;
for(int i=0;i<n;i++){
int cost,recharge;
cin>>cost>>recharge;
if(recharge > cost){
v1.push_back(make_pair(cost,recharge));
}else{
v2.push_back(make_pair(recharge,cost));
}
diff += (cost-recharge);
}
sort(v1.begin(), v1.end());
sort(v2.begin(), v2.end());
if(v2.size() > 0)diff += v2[0].first;
int max_req = diff, req = 0,cur = 0;
for(int i=0; i<v1.size(); i++){
req = v1[i].first - cur;
max_req = max(max_req, req);
cur += v1[i].second-v1[i].first;
}
cout<<max(max_req,diff)<<endl;
return 0;
}
(This is a wiki post: you are invited to edit, and don't need much reputation to do so without involving a moderator.)
Working efficiently means accomplishing the task at hand, with no undue effort. Aspects here:
the OP asks for guidance in approaching this problem to find optimal solution - not for a solution (as this entirely similar, older question does).
the problem statement asks for the minimum value of M - not an optimal order of calls or how to find that.
To find the minimum balance initially required, categorise the relatives/(T, X)-pairs/calls (the order might have a meaning, if not for the problem as stated)
T < X Leaves X-T more for calls to follow. Do in order of increasing cost.
Start assuming an initial balance of 1. For each call, if you can afford it, subtract its cost, add its refund and be done accounting for it. If you can't afford it (yet), put it on hold/the back burner/in a priority queue. At the end of "rewarding calls", remove each head of the queue in turn, accounting for necassary increases in intitial balance.
This part ends with a highest balance, yet.
T = X No influence on any other call. Just do at top balance, in any order.
The top balance required for the whole sequence can't be lower than the cost of any single call, including these.
T > X Leaves T-X less for subsequent calls. Do in order of decreasing refund.
(This may, as any call, go to a balance of zero before refund.
As order of calls does not change the total cost, the ones requiring the least initial balance will be those yielding the lowest final one. For the intermediate balance required by this category, don't forget that least refund.)
Combine the requirements from all categories.
Remember the request for guidance.

Algorithm interview from Google

I am a long time lurker, and just had an interview with Google where they asked me this question:
Various artists want to perform at the Royal Albert Hall and you are responsible for scheduling
their concerts. Requests for performing at the Hall are accommodated on a first come first served
policy. Only one performance is possible per day and, moreover, there cannot be any concerts
taking place within 5 days of each other
Given a requested time d which is impossible (i.e. within 5 days of an already sched-
uled performance), give an O(log n)-time algorithm to find the next available day d2
(d2 > d).
I had no clue how to solve it, and now that the interview is over, I am dying to figure out how to solve it. Knowing how smart most of you folks are, I was wondering if you can give me a hand here. This is NOT for homework, or anything of that sort. I just want to learn how to solve it for future interviews. I tried asking follow up questions but he said that is all I can tell you.
You need a normal binary search tree of intervals of available dates. Just search for the interval containing d. If it does not exist, take the interval next (in-order) to the point where the search stopped.
Note: contiguous intervals must be fused together in a single node. For example: the available-dates intervals {2 - 15} and {16 - 23} should become {2 - 23}. This might happen if a concert reservation was cancelled.
Alternatively, a tree of non-available dates can be used instead, provided that contiguous non-available intervals are fused together.
Store the scheduled concerts in a binary search tree and find a feasible solution by doing a binary search.
Something like this:
FindDateAfter(tree, x):
n = tree.root
if n.date < x
n = FindDateAfter(n.right, x)
else if n.date > x and n.left.date < x
return n
return FindDateAfter(n.left, x)
FindGoodDay(tree, x):
n = FindDateAfter(tree, x)
while (n.date + 10 < n.right.date)
n = FindDateAfter(n, n.date + 5)
return n.date + 5
I've used a binary search tree (BST) that holds the ranges for valid free days that can be scheduled for performances.
One of the ranges must end with int.MaxValue, because we have an infinite amount of days so it can't be bound.
The following code searches for the closest day to the requested day, and returns it.
The time complexity is O(H) when H is the tree height (usually H=log(N), but can become H=N in some cases.).
The space complexity is the same as the time complexity.
public static int FindConcertTime(TreeNode<Tuple<int, int>> node, int reqDay)
{
// Not found!
if (node == null)
{
return -1;
}
Tuple<int, int> currRange = node.Value;
// Found range.
if (currRange.Item1 <= reqDay &&
currRange.Item2 >= reqDay)
{
// Return requested day.
return reqDay;
}
// Go left.
else if (currRange.Item1 > reqDay)
{
int suggestedDay = FindConcertTime(node.Left, reqDay);
// Didn't find appropriate range in left nodes, or found day
// is further than current option.
if (suggestedDay == -1 || suggestedDay > currRange.Item1)
{
// Return current option.
return currRange.Item1;
}
else
{
// Return suggested day.
return suggestedDay;
}
}
// Go right.
// Will always find because the right-most node has "int.MaxValue" as Item2.
else //if (currRange.Item2 < reqDay)
{
return FindConcertTime(node.Right, reqDay);
}
}
Store the number of used nights per year, quarter, and month. To find a free night, find the first year that is not fully booked, then the quarter within that year, then the month. Then check each of the nights in that month.
Irregularities in the calendar system makes this a little tricky so instead of using years and months you can apply the idea for units of 4 nights as "month", 16 nights as "quarter", and so on.
Assume, at level 1 all schedule details are available.
Group schedule of 16 days schedule at level 2.
Group 16 level 2 status at level 3.
Group 16 level 3 status at level 4.
Depends on number of days that you want to expand, increase the level.
Now search from higher level and do binary search at the end.
Asymtotic complexity:-
It means runtime is changing as the input grows.
suppose we have an input string “abcd”. Here we traverse through each character to find its length thus the time taken is proportional to the no of characters in the string like n no of char. Thus O(n).
but if we put the length of the string “abcd” in a variable then no matter how long the string be we still can find the length of thestring by looking at the variable len. (len=4).
ex: return 23. no matter what you input is we still have the output as 23.
thus the complexity is O(1). Thus th program will be running in a constant time wrt input size.
for O(log n) - the operations are happening in logarithmic steps.
https://drive.google.com/file/d/0B7eUOnXKVyeERzdPUE8wYWFQZlk/view?usp=sharing
Observe the image in the above link. Over here we can see the bended line(logarithmic line). Here we can say that for smaller inputs the O(log n) notation works good as the time taken is less as we can see in the bended line but when the input grows the linear notation i.e O(n) is considered as better way.
There are also the best and worst case scenarios to be seen. Like the above example.
You can also refer to this cheat for the algorithms: http://bigocheatsheet.com/
It was already mentioned above, but basically keep it simple with a binary tree. You know a binary tree has log N complexity. So you already know what algorithm you need to use.
All you have to do is to come up with a tree node structure and use binary tree insertion algorithm to find next available date:
A possible one:
The tree node has two attributes: d (date of the concert) and d+5 (end date for the blocking period of 5 days). Again to keep it simple, use a timestamp for the two date attributes.
Now it is trivial to find next available date by using binary tree inorder insertion algorithm with initial condition of root = null.
Why not try to use Union-Find? You can group each concert day + the next 5 days as part of one set and then perform a FIND on the given day which would return the next set ID which would be your next concert date.
If implemented using a tree, this gives a O(log n) time complexity.

Resources