How to solve USACO 2013-Perimeter-Silver Recursively - c++

So I was solving this USACO 2013 February Silver Contest - Perimeter - Problem 1.
Link to the problem: Problem Link
Link to the bronze version of this problem: Problem Link
Link to solutions: Silver - Link to Solution Bronze - Link to Solution
The problem:
Problem 1: Perimeter [Brian Dean, 2013]
Farmer John has arranged N hay bales (1 <= N <= 50,000) in the middle of
one of his fields. If we think of the field as a 1,000,000 x 1,000,000
grid of 1 x 1 square cells, each hay bale occupies exactly one of these
cells (no two hay bales occupy the same cell, of course).
FJ notices that his hay bales all form one large connected region, meaning
that starting from any bale, one can reach any other bale by taking a
series of steps either north, south, east, or west onto directly adjacent
bales. The connected region of hay bales may however contain "holes" --
empty regions that are completely surrounded by hay bales.
Please help FJ determine the perimeter of the region formed by his hay
bales. Note that holes do not contribute to the perimeter.
PROBLEM NAME: perimeter
INPUT FORMAT:
Line 1: The number of hay bales, N.
Lines 2..1+N: Each line contains the (x,y) location of a single hay
bale, where x and y are integers both in the range
1..1,000,000. Position (1,1) is the lower-left cell in FJ's
field, and position (1000000,1000000) is the upper-right cell.
SAMPLE INPUT (file perimeter.in):
8
10005 200003
10005 200004
10008 200004
10005 200005
10006 200003
10007 200003
10007 200004
10006 200005
INPUT DETAILS:
The connected region consisting of hay bales looks like this:
XX
X XX
XXX
OUTPUT FORMAT:
Line 1: The perimeter of the connected region of hay bales.
SAMPLE OUTPUT (file perimeter.out):
14
OUTPUT DETAILS:
The length of the perimeter of the connected region is 14 (for example, the
left side of the region contributes a length of 3 to this total). Observe
that the hole in the middle does not contribute to this number.
What I did
I went ahead with a recursive solution to the problem which goes like this :
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
#define rep(i,a,b) for(auto (i)=a;i<b;i++)
#define list(i,N) for(auto (i)=0;i<N;i++)
typedef long long ll;
typedef vector<ll> vi;
typedef pair<ll,ll> pi;
#define mp make_pair
#define pb push_back
#define int ll
#define INF 1e18+5
#define mod 1000000007
//One map for storing whether a cell has hay bale or not
//And the other for visited - whether a cell has been visited or not
map<pi,bool> vis;
map<pi,bool> exists;
int ans = 0;
void solve(int i, int j){
//Check about the visited stuff
if(vis[mp(i,j)]) return;
vis[mp(i,j)] = true;
//Find the answer now
ans += 4;
if(exists[mp(i-1,j)]){
--ans; solve(i-1,j);
}
if(exists[mp(i+1,j)]){
--ans; solve(i+1,j);
}
if(exists[mp(i,j+1)]){
--ans; solve(i,j+1);
}
if(exists[mp(i,j-1)]){
--ans; solve(i,j-1);
}
}
int32_t main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int N; cin >> N;
int first, second; //the starting point where we start the function...
while(N--){
int a,b; cin >> a >> b;
first = a; second = b; //in the end, it is just the coordinate specified in the last in the input...
exists[mp(a,b)] = true; //Hay Bale exists...
}
solve(first,second);
cout << ans << "\n";
return 0;
}
Basically, what I am doing is :
Start at a cell.
First, check if the cell has been previously visited. If yes, return. If not, make it visited.
Add 4 to the counter for all the four sides.
Look around the cell to all its neighbouring cells. If the cell also has haybales, subtract 1 from the counter (no need for adding boundary) and then goto 2.
The problem which I am facing
Observe that this code also counts the boundary required inside the hole. BUT we don't need to include that into our answer. I, however, don't know how to exclude that from our answer...
Why I mentioned the Bronze Problem
If you see the solution of the Bronze Problem (which is just the same problem but with different constraints), Mr Brian Dean also implements this sort of a recursive solution here which is similar to what I'm doing in my code. The code is down below :
#include <stdio.h>
#define MAX_N 100
int already_visited[MAX_N+2][MAX_N+2];
int occupied[MAX_N+2][MAX_N+2];
int perimeter;
int valid(int x, int y)
{
return x>=0 && x<=MAX_N+1 && y>=0 && y<=MAX_N+1;
}
void visit(int x, int y)
{
if (occupied[x][y]) { perimeter++; return; }
if (already_visited[x][y]) return;
already_visited[x][y] = 1;
if (valid(x-1,y)) visit(x-1,y);
if (valid(x+1,y)) visit(x+1,y);
if (valid(x,y-1)) visit(x,y-1);
if (valid(x,y+1)) visit(x,y+1);
}
int main(void)
{
int N, i, x, y;
freopen ("perimeter.in", "r", stdin);
freopen ("perimeter.out", "w", stdout);
scanf ("%d", &N);
for (i=0; i<N; i++) {
scanf ("%d %d", &x, &y);
occupied[x][y] = 1;
}
visit(0,0);
printf ("%d\n", perimeter);
return 0;
}
Why this solution does not work for the Silver
This is because the constraints in the Silver version of the problem which I'm solving has higher constraints but the same time limit. This times out the code.
So, I would be grateful if anybody could help me solve this problem in order to exclude the perimeter taken up by the hole in the middle.

Your solution is quite similar to the second one posted. But instead of walking on the bales, you walk on the perimeter:
void solve(int i, int j){
if(vis[mp(i,j)]) return;
if(exists[mp(i,j)]) return;
if(there_is_no_bale_next_to(i,j)) return; // consider all 8 directions
vis[mp(i,j)] = true;
ans ++;
solve(i-1,j);
solve(i+1,j);
solve(i,j+1);
solve(i,j-1);
}
You first run solve on a point definitely on perimeter(like the westmost point).

The problem with your solution is that it targets at the 'X' points, which will inevitably count the holes as well. Please consider to launch a floodfill that moves around the object without actually getting into it. My solution below implements this idea, so holes are not being counted. Brian Dean's solution in the official editorial is also based on this idea, so you should check out that as well.
#include<bits/stdc++.h>
using namespace std;
int n, ans = 0;
map<pair<int,int>, bool> m, vis;
pair<int,int> p = {INT_MAX, INT_MAX};
bool adj (int i, int j) {
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
if (!x & !y) continue;
if (m[{i + x, j + y}]) return true;
}
}
return false;
}
int get_cnt (int i, int j) {
int res = 0;
if (m[{i, j + 1}]) res++;
if (m[{i, j - 1}]) res++;
if (m[{i + 1, j}]) res++;
if (m[{i - 1, j}]) res++;
return res;
}
void floodfill (int i, int j) {
if (m[{i, j}] || vis[{i, j}] || !adj(i, j)) return;
vis[{i, j}] = true;
ans += get_cnt(i, j);
floodfill (i, j + 1);
floodfill (i, j - 1);
floodfill (i + 1, j);
floodfill (i - 1, j);
}
int main () {
cin >> n;
for (int i = 0; i < n; i++) {
int x, y;
cin >> x >> y;
m[{x, y}] = true;
p = min(p, {x, y});
}
floodfill (p.first - 1, p.second);
cout << ans << endl;
}

Related

Algorithm to divide a black-and-white chocolate bar

Problem description:
There's a chocolate bar that consists of m x n squares. Some of the squares are black, some are white. Someone breaks the chocolate bar along its vertical axis or horizontal axis. Then it is broken again along its vertical or horizontal axis and it's being broken until it can broken into a single square or it can broken into squares that are only black or only white. Using a preferably divide-and-conquer algorithm, find the number of methods a chocolate bar can be broken.
Input:
The first line tells you the m x n dimensions of the chocolate bar. In the next m lines there are n characters that tell you how does the chocolate bar look. Letter w is a white square, letter b is a black square.
for example:
3 2
bwb
wbw
Output:
the number of methods the chocolate bar can be broken:
for the example above, it's 5 (take a look at the attached picture).
I tried to solve it using an iterative approach. Unfortunately, I couldn't finish the code as I'm not yet sure how to divide the the halves (see my code below). I was told that an recursive approach is much easier than this, but I have no idea how to do it. I'm looking for another way to solve this problem than my approach or I'm looking for some help with finishing my code.
I made two 2D arrays, first for white squares, second for black squares. I'm making a matrix out of the squares and if there's a chocolate of such or such color, then I'm marking it as 1 in the corresponding array.
Then I made two arrays of the two cumulative sums of the matrices above.
Then I created a 4D array of size [n][m][n][m] and I made four loops: first two (i, j) are increasing the size of an rectangular array that is the size of the searching array (it's pretty hard to explain...) and two more loops (k, l) are increasing the position of my starting points x and y in the array. Then the algorithm checks using the cumulative sum if in the area starting at position kxl and ending at k+i x l+j there is one black and one white square. If there is, then I'm creating two more loops that will divide the area in half. If in the two new halves there are still black and white squares, then I'm increasing the corresponding 4D array element by the number of combinations of the first halve * the number of combinations of the second halve.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
int counter=0;
int n, m;
ifstream in;
in.open("in.txt");
ofstream out;
out.open("out.txt");
if(!in.good())
{
cout << "No such file";
return 0;
}
in >> n >> m;
int whitesarray[m][n];
int blacksarray[m][n];
int methodsarray[m][n][m][n];
for(int i=0; i<m; i++)
{
for(int j=0; j<n; j++)
{
whitesarray[i][j] = 0;
blacksarray[i][j] = 0;
}
}
while(in)
{
string colour;
in >> colour;
for (int i=0; i < colour.length(); i++)
{
if(colour[i] == 'c')
{
blacksarray[counter][i] = 1;
}
if(colour[i] == 'b')
{
whitesarray[counter][i] = 1;
}
}
counter++;
}
int whitessum[m][n];
int blackssum[m][n];
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
{
if(i-1 == -1 && j-1 == -1)
{
whitessum[i][j] = whitesarray[i][j];
blackssum[i][j] = blacksarray[i][j];
}
if(i-1 == -1 && j-1 != -1)
{
whitessum[i][j] = whitessum[i][j-1] + whitesarray[i][j];
blackssum[i][j] = blackssum[i][j-1] + blacksarray[i][j];
}
if(j-1 == -1 && i-1 != -1)
{
whitessum[i][j] = whitessum[i-1][j] + whitesarray[i][j];
blackssum[i][j] = blackssum[i-1][j] + blacksarray[i][j];
}
if(j-1 != -1 && i-1 != -1)
{
whitessum[i][j] = whitessum[i-1][j] + whitessum[i][j-1] - whitessum[i-1][j-1] + whitesarray[i][j];
blackssum[i][j] = blackssum[i-1][j] + blackssum[i][j-1] - blackssum[i-1][j-1] + blacksarray[i][j];
}
}
}
int posx=0;
int posy=0;
int tempwhitessum=0;
int tempblackssum=0;
int k=0, l=0;
for (int i=0; i<=m; i++)
{
for (int j=0; j<=n; j++) // wielkosc wierszy
{
for (posx=0; posx < m - i; posx++)
{
for(posy = 0; posy < n - j; posy++)
{
k = i+posx-1;
l = j+posy-1;
if(k >= m || l >= n)
continue;
if(posx==0 && posy==0)
{
tempwhitessum = whitessum[k][l];
tempblackssum = blackssum[k][l];
}
if(posx==0 && posy!=0)
{
tempwhitessum = whitessum[k][l] - whitessum[k][posy-1];
tempblackssum = blackssum[k][l] - blackssum[k][posy-1];
}
if(posx!=0 && posy==0)
{
tempwhitessum = whitessum[k][l] - whitessum[posx-1][l];
tempblackssum = blackssum[k][l] - blackssum[posx-1][l];
}
if(posx!=0 && posy!=0)
{
tempwhitessum = whitessum[k][l] - whitessum[posx-1][l] - whitessum[k][posy-1] + whitessum[posx-1][posy-1];
tempblackssum = blackssum[k][l] - blackssum[posx-1][l] - blackssum[k][posy-1] + blackssum[posx-1][posy-1];
}
if(tempwhitessum >0 && tempblackssum > 0)
{
for(int e=0; e<n; e++)
{
//Somehow divide the previously found area by two and check again if there are black and white squares in this area
}
for(int r=0; r<m; r++)
{
//Somehow divide the previously found area by two and check again if there are black and white squares in this area
}
}
}
}
}}
return 0;
}
I strongly recommend recursion for this. In fact, Dynamic Programming (DP) would also be very useful, especially for larger bars. Recursion first ...
Recursion
Your recursive routine takes a 2-D array of characters (b and w). It returns the number of ways this can be broken.
First, the base cases: (1) if it's possible to break the given bar into a single piece (see my comment above, asking for clarification), return 1; (2) if the array is all one colour, return 1. For each of these, there's only one way for the bar to end up -- the way it was passed in.
Now, for the more complex case, when the bar can still be broken:
total_ways = 0
for each non-edge position in each dimension:
break the bar at that spot; form the two smaller bars, A and B.
count the ways to break each smaller bar: count(A) and count(B)
total_ways += count(A) * count(B)
return total_ways
Is that clear enough for the general approach? You still have plenty of coding to do, but using recursion allows you to think of only the two basic ideas when writing your function: (1) How do I know when I'm done, and what trivial result do I return then? (2) If I'm not done, how do I reduce the problem?
Dynamic Programming
This consists of keeping a record of situations you've already solved. The first thing you do in the routine is to check your "data base" to see whether you already know this case. If so, return the known result instead of recomputing. This includes the overhead of developing and implementing said data base, probably a look-up list (dictionary) of string arrays and integer results, such as ["bwb", "wbw"] => 5.

Simulating a random walk scenario on a 4x4 board

The problem I am working on is as follows. Imagine a 4x4 chess board on top of which you place a king. The probability of you placing the king on each of the squares is one of the inputs (not necessarily the same for all the squares). The king has to make n number of moves (n is an input). The goal is to run an 'experiment' to find the probability after n moves.
My friend solved the problem by creating a general formula using linear algebra. As a challenge/verification of his answer I want to make this program in c++.
We both start with making one generalization. That is since the board is symmetrical we only consider if the king is at a side, corner or middle square of the board.
C S S C
S M M S
S M M S
C S S C
Therefore, we input only P(S_{initial}), P(C_{initial}), P(M_{initial}), the number of moves the king makes, and the number of 'experiments' we make.
The code for my program is below. My results disagreed with my friend's, so I checked my code by setting n to 1 and P(S_{initial}), P(C_{initial}) and P(M_{initial}) to 1/2, 1/4, and 1/4, respectively. By conditional probability I know that P(S)=59/120, P(C)=21/160, P(M)=181/481. My computations do not agree, so I am sure there is a bug or error in my code, but I cannot track it down. I appreciate any help.
Also I know my code is scruffy and inefficient so I appreciate comments about how to improve it. Thanks for your help.
EDIT: To input the initial probabilities I input 2, 1 and 1 for S, C and M, respectively.
EDIT2: Turned out that I used "=" instead of the operator "==" in my if statements. Thank you #Christopher Oicles. Everything works now as expected.
#include <iostream>
#include <string>
#include <cstdlib>
#include <cmath>
#include <stdio.h>
#include <time.h>
using namespace std;
int S, C, M; //probability 'ratios', i.e. prob of S is S/(S+C+M)
int n; // number of steps
int trials;
int initial(int a,int b,int c); // this 'throws the die' to find where to start and returns 0 for side, 1 for corner, 2 for middle
int step(int a); // this throws the die to make a step and returns the same format
int trial(); //this makes n number of steps, starting at initial(a,b,c) and returns 0,1,2
double data[]={0,0,0}; // the result of the experiment, each element holds the number of times a trial returned the S,C,M where number of s = data[0], I increment this by one every time I run trial();
int main()
{
srand(time(NULL));
for(int i=0;i<3;i++) //reset data array
data[i]=0;
std::cout << "Enter probability ratio of S:";
std::cin >> S;
std::cout << "Enter probability ratio of C:";
std::cin >> C;
std::cout << "Enter probability ratio of M:";
std::cin >> M;
std::cout << "Enter number of steps per trial:";
std::cin >> n;
std::cout << "Enter number of trials:";
std::cin >> trials;
for(int i=0;i<trials;i++)
data[trial()]++;
for(int i=0;i<3;i++)
std::cout << data[i]/trials << " \n";
for(int i=0;i<3;i++)
std::cout<<data[i]<<" ";
cout << "\n \n";
}
int trial(){
int current;// the current place S, C or M or 0,1,2
int next;
current = initial(S,C,M);
for(int i=0;i<n;i++)
{next = step(current);
current = next;}
return current;
}
int initial(int side,int corner,int middle){
int t = rand() % (side+corner+middle); //generates a random number from zero to a+b+c-1
//now we apply the probability
if(t < side)
return 0; //side
if(t >= side && t < (side+corner))
return 1; //corner
if(t>=(side+corner))
return 2; //middle
}
int step(int a){
int t;
switch(a){
case 0: //we are on a side
{t = rand()%5;
if(t < 2){return 0;} //2/5 chance to go to a side
if(t = 2){return 1;} //1/5 chance to go to a corner
if(t > 2){return 2;} //2/5 chance to go to a middle
break;}
case 1: //we are on corner
{t = rand()%3;
if(t < 2){return 0;} //2/3 chance to go to side
if(t = 2){return 2;} //1/3 chance to go to middle
break;}
case 2: //we are on middle
{t = rand()%8;
if(t < 4){return 0;} //1/2 chance go to side
if(t = 4){return 1;} //1/8 chance of corner
if(t > 4){return 2;} //3/8 chance of middle
break;}
}
}

Finding minimum necessary volume of gas container

I found this problem somewhere in a contest and haven't been able to come up with a solution yet.
There is the N cities with coordinates (x, y). I have to go from first
city and reach the second city. There is a gas station in each city.
So I have to find minimum necessary volume of gas container to reach
the final city.
For example:
Input:
3
17 4
19 4
18 5
Output:
1.414
Here, my way is: 1->3->2
I'm using simple brute-force method, but it so slow. How can I optimize my code?
Maybe there is a better solution?
#include <iostream>
#include <algorithm>
#include <stack>
#include <math.h>
#include <cstring>
#include <iomanip>
#include <map>
#include <queue>
#include <fstream>
using namespace std;
int n, used[203];
double min_dist;
struct pc {
int x, y;
};
pc a[202];
double find_dist(pc a, pc b) {
double dist = sqrt( (a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y) );
return dist;
}
void functio(double d, int used[], int k, int step) {
used[k] = 1;
if(k == 1) {
if(d < min_dist) {
min_dist = d;
}
used[k] = 0;
return;
}
for(int i = 1; i < n; ++i) {
if(i != k && used[i] == 0) {
double temp = find_dist(a[k], a[i]);
if(temp > d) {
if(temp < min_dist)
functio(temp, used, i, step + 1);
}
else {
if(d < min_dist)
functio(d, used, i, step + 1);
}
}
}
used[k] = 0;
}
int main() {
cin >> n;
for(int i = 0; i < n; ++i)
cin >> a[i].x >> a[i].y;
min_dist = 1000000;
memset(used, 0, sizeof(used));
functio(0, used, 0, 0);
cout << fixed << setprecision(3) << min_dist << endl;
}
The minimum spanning tree has the neat property of encoding all of the paths between vertices that minimize the length of the longest edge on the path. For Euclidean MST, you can compute the Delaunay triangulation and then run your favorite O(m log n)-time algorithm (on a graph with m = O(n) edges) for a total running time of O(n log n). Alternatively, you could run Prim with a naive priority queue for an O(n^2)-time algorithm with a good constant (especially if you exploit SIMD).
So what you are trying to optimise in your algorithm is the longest distance you travel between two cities. Because that's how big your gas tank needs to be.
This is a variation on shortest path, because there you're trying to optimise the enire path length.
I think you could get away with this:
make a list of edges. (the distance between each pair of cities)
remove the longest edge from the list, unless this causes the destination to become unreachable.
once you cannot remove the longest path anymore, that means that this is your limiting factor in going to your destination. The rest of the route doesn't matter anymore.
Then in the end you should have a list of edges that make up a path between source and destination.
I haven't proven this solution to be optimal, so no guarantees. But consider this: if you remove the longest path, there are only shorter paths to take, so the maximum leg distance won't increase.
About the complexity, time complexity is O(n log n) because you have to sort the edges.
Memory complexity is O(n^2)
This is probably not the most efficient algorithm, because it is a graph-algorithm, and makes no use of the fact that the cities are on an euclidean plane. There is probably some optimisation there...
You can reduce time complexity to O(n^2*log(n)) using binary search which will run within the 1 second time limit. The idea behind the binary search is if we can reach city 2 from city 1 using x volume there is no need to check for higher volume container. If we cannot reach using using this then we need more than x volume. To check if we can reach city 2 using x volume you can use BFS. If two cities are within x distance of each other then its possible to move from one to the another and we can say they are connected by edge.
Code:
int vis[203];
double eps=1e-8;
struct pc {
double x, y;
};
double find_dist(pc &a, pc &b) {
double dist=sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
return dist;
}
bool can(vector<pc> &v, double x) { // can we reach 2nd city with volume x
int n=v.size();
vector<vector<int>> graph(n, vector<int>(n, 0)); // graph in adjacency matrix form
// set edges in graph
for(int i=0; i<n; i++) {
for(int j=0; j<n; j++) {
if(i==j) continue; //same city
double d=find_dist(v[i], v[j]);
if(d<=x) graph[i][j]=1; // can reach from city i to city j using x volume
}
}
// perform BFS
memset(vis, 0, sizeof(vis));
queue<int> q;
q.push(0); // we start from city 0 (0 absed index)
vis[0]=1;
while(!q.empty()) {
int top=q.front();
q.pop();
if(top==1) return true; // can reach city 2 (1 in 0-based index)
for(int i=0; i<n; i++) {
if(top!=i && !vis[i] && graph[top][i]==1) {
q.push(i);
vis[i]=1;
}
}
}
return false; // can't reach city 2
}
double calc(vector<pc> &v) { // calculates minimum volume using binary search
double lo=0, hi=1e18;
while(abs(hi-lo)>eps) {
double mid=(lo+hi)/2;
if(can(v, mid)) {
hi=mid; // we need at most x volume
} else{
lo=mid; // we need more than x volumer
}
}
return lo;
}

How do I solve this p‌r‌o‌b‌l‌e‌m using Dynamic Programming Top Down approach?

I'm trying to solve a problem from Codeforces (http://codeforces.com/problemset/problem/189/A)
Here's the problem statement:
Polycarpus has a ribbon, its length is n. He wants to cut the ribbon in a way that fulfils the following two conditions:
After the cutting each ribbon piece should have length a, b or c.
After the cutting the number of ribbon pieces should be maximum.
Help Polycarpus and find the number of ribbon pieces after the required
cutting.
Input
The first line contains four space-separated integers n, a, b and c (1 ≤ n, a, b, c ≤ 4000) — the length of the original ribbon and the acceptable lengths of the ribbon pieces after the cutting, correspondingly. The numbers a, b and c can coincide.
Output
Print a single number — the maximum possible number of ribbon pieces. It is guaranteed that at least one correct ribbon cutting exists.
Sample Input
5 5 3 2
Sample Output
2
I tried to solve this problem using Dynamic Programming (Topdown approach). But I'm not able to get the correct answer. There might be something wrong with the recursive function. Here's my code:
#include<bits/stdc++.h>
using namespace std;
int n,s;
int a[3];
int val,m=-1;
int dp(int n)
{
if(n==0)
return 0;
for(int i=0;i<3;i++)
{
if(n>=a[i])
{
val=1+dp(n-a[i]);
}
}
if(val>m)
m=val;
return m;
}
int main()
{
scanf("%d %d %d %d",&n,&a[0],&a[1],&a[2]);
cout<<dp(n)<<endl;
return 0;
}
What is the problem in the above approach?
There are several problems:
Wrong Search
In your lines
for(int i=0;i<3;i++)
{
if(n>=a[i])
{
val=1+dp(n-a[i]);
}
}
if(val>m)
m=val;
You should be checking for the maximum of the different vals obtained for the different choices of i.
Wrong Termination
If the length is not 0 and no ribbon can be cut, you should return something like minus infinity. You currently return m which is initially -1 (more on this later). This is wrong, and for long ribbons will essentially ensure that you just choose the minimum of a, b, and c.
Use of Globals
Some globals, e.g., m are initialized once but are modified by the recursion. It's not "just" bad programming habits - it's not doing what you want.
No Reuse
By calling the recursion unconditionally, and not reusing previous calls, your running time is needlessly high.
int main() {
int n, a, b, c;
scanf("%d %d %d %d", &n, &cuts[0], &cuts[1], &cuts[2]);
sort(cuts, cuts + 3);
for (int i = 0; i <= n; i++) {
max_cuts[i] = INT_MIN;
}
max_cuts[0] = 0;
max_cuts[cuts[0]] = 1;
max_cuts[cuts[1]] = 1;
max_cuts[cuts[2]] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < 3; j++) {
if (cuts[j] > i) break;
max_cuts[i] = max(max_cuts[i - cuts[j]] + 1, max_cuts[i]);
}
}
printf("%d\n", max_cuts[n]);
return 0;
}
#Ami Tavory correctly suggested the problems with your recursive approach. May be my solution below can help you understand better how to form states and check bounds:
int main()
{
int n, a, b, c;
cin >> n >> a >> b >> c;
const int l = n + 1;
int sum[l];
fill(sum, sum+l, INT_MIN);
sum[0] = 0;
for(int i=1; i<=n; i++)
{
if(i - a >= 0)
{
sum[i] = sum[i-a] + 1;
}
if(i - b >= 0 && sum[i-b] + 1 > sum[i])
{
sum[i] = sum[i-b] + 1;
}
if(i - c >= 0 && sum[i-c] + 1 > sum[i])
{
sum[i] = sum[i-c] + 1;
}
}
cout << sum[n] << endl;
return 0;
}
Simply at each sum[i], we are maximizing the number of cuts. So, at sum[i], we are storing the max(sum[i-a]+1, sum[i-b]+1, sum[i-c]+1).
Other than this, there are just bound checks.
you can solve this problem through top down approach.A dp problem always check all the possible cases then gives us the optimal solution.so here is the code
#include<bits/stdc++.h>
using namespace std;
int a,b,c;
int DP[4001];
int solve(int n){
if(n == 0)return 0;
if(n<0) return INT_MIN;
if(DP[n] != -1)return DP[n];
else{
DP[n] = max(1+solve(n-a),max(1+solve(n-b),1+solve(n-c)));
return DP[n];
}
}
int main(){
int n,x;
cin>>n>>a>>b>>c;
for(int i = 0;i<4001;++i){
DP[i] = -1;
}
x = solve(n);
cout<<x;
}

calculate the sum of diagonals in a matrix

I need to calculate the sum of two diagonals in a matrix in C++, I already have a solution for that but I must be dumb because I cant understand what it is doing, so I would like to know if there is another version which I can understand. here is the code which does the job:
cout<<"Jepi rangun e matrices"<<endl; // pra bejme manipulim me matrice katrore ku rreshtat=kolonat
cin>>n;
cout<<"Tani jepi elementet e matrices"<<endl; // lexohet matrica
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
cin>>a[i][j];
}
d=0;
s=0; // ketu e keni kushtin si dhe mbledhjen per te dy diagonalet me dy variabla te ndryshme
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(i==j)
d=d+a[i][j];
if(j==n-i+1 || i==n-j+1)
s=s+a[i][j];
}
The part that is difficult to understand is
if(j==n-i+1 || i==n-j+1)
s=s+a[i][j];
Here is the entire code that I changed but it doesnt work for the secondary diagonal:
#include <iostream>
using namespace std;
int main()
{
int d=0,s=0; // ketu e keni kushtin si dhe mbledhjen per te dy diagonalet me dy variabla te ndryshme
int i,j,n;
int a[5][5];
cout<<"Jepi rangun e matrices"<<endl; // pra bejme manipulim me matrice katrore ku rreshtat=kolonat
cin>>n;
cout<<"Tani jepi elementet e matrices"<<endl; // lexohet matrica
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
cin>>a[i][j];
}
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(i==j)
d+=a[i][j]; //principal diagonal
if(i+j==n-1)
s+=a[i][j];//secondary diagonal
}
}
cout << d << endl;
cout << s << endl;
cin.get();
cin.get();
return 0;
}
It would be nice to have comments in English, but, the your code does (second loop):
browse all rows
browse all cells
if i == j (is in main diagonal):
increase one sum
if i == n - i + 1 (the other diagonal)
increase the second sum
The much nicer and much more effective code (using n, instead of n^2) would be:
for( int i = 0; i < n; i++){
d += a[i][i]; // main diagonal
s += a[i][n-i-1]; // second diagonal (you'll maybe need to update index)
}
This goes straight trough the diagonals (both at the one loop!) and doesn't go trough other items.
EDIT:
Main diagonal has coordinates {(1,1), (2,2), ..., (i,i)} (therefor i == j).
Secondary diagonal has coordinates (in matrix 3x3): {(1,3), (2,2),(3,1)} which in general is: {(1,n-1+1), (2, n-2+1), ... (i, n-i+1), .... (n,1)}. But in C, arrays are indexed from 0, not 1 so you won't need that +1 (probably).
All those items in secondary diagonal than has to fit condition: i == n - j + 1 (again due to C's indexing from 0 +1 changes to -1 (i=0,, n=3, j=2, j = n - i - 1)).
You can achieve all this in one loop (code above).
int diag1=0;
int diag2=0;
for (i=0;i<n;i++)
for (j=0;j<n;j++){
if(i==j) diag1+=a[i][j]; //principal diagonal
if(i+j==n-1) diag2+=a[i][j];//secondary diagonal
}
To understand this algorithm better you should paint a matrix on you notebook and number it's elements with their position in matrix,then apply the algorithm step by step.I'm 100% sure that you will understand
How about I try to explain this version? :D
There are 3 important parts of the code:
inputing the matrix
calculating major diagonal ( \ direction)
calculating minor diagonal ( / direction)
And here they are, explained:
// input elements
for(i=1;i<=n;i++) // from left to right
{
for(j=1;j<=n;j++) // from up to down
cin>>a[i][j]; // input element at (i,j) position
}
Here, d and s contain the inter-values of major and minor diagonal respectively. At the end of 2 loops, they will contain the results
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
if(i==j) // major diagonal - if coordinates are the same
d=d+a[i][j]; // e.g. (1,1), (2,2)
if(j==n-i+1 || i==n-j+1) // coordinates of the minor diagonal - check
s=s+a[i][j]; // e.g. n=3 (3,1) (2,2) ...
}
Hope this helps.
Note that this code starts matrix coordinates at 1 instead of 0, so you will actually need to allocate (n+1)x(n+1) space for the matrix:
double a[n+1][n+1];
before using it.
Also, the code you gave is not most effective. It has O(n^2) complexity, while the task can be done in O(n) like so:
// matrix coordinates now start from 0
for (int i=0; i < n; ++i){
d += a[i][i]; // major
s += a[i][n-1-i]; // minor
}
int num[5][5]={0}; //decleration
int i=0,j=0,sum=0;
for (int i=0;i<5;i++)
{
for (int j=0;j<5;j++)
{
cin>>num[i][j];
} //Taking Matrix input
}
cout<<endl<<"The Matrix is "<<endl;
for (int i=0;i<5;i++)
{
for (int j=0;j<5;j++)
{
cout<<num[i][j]<<" ";
}
cout<<endl; //Displaying the Matrix
}
cout<<endl<<"The sum of diagonals of the matrix is "<<endl;
if(i==j)
{
for (i=0;i<5;i++)
{
for (j=0;j<5;j++)
{
if (i==j) //This loop works where i and j will be equal
{
sum=sum+num[i][j];
}
}
}
cout<<sum;
}
else //Some times the user creates 4 x 3 matrix or so than diagonals not match so. . .
{
cout<<"The sum is not Possible";
}
you must use i + j == n + 1 instead of i + j == n - 1 for secondary diagonal i.e
for(i = 1; i <= n; i++)
{
for(j = 1; j <= n; j++)
{
if(i == j)
d += a[i][j]; //principal diagonal
if(i + j == n+1)
s += a[i][j];//secondary diagonal
}
}