O(N^2) shortest path algorithm - c++

The problem states that we have a set of points with their coordinates and that we have to find the shortest path always beginning at (0,0) reaching a destination and going back again to (0,0) passing all inbetween points only once.
The input looks like this
on the first line are the number of inbetween points, on the second the coordinates of the destination and then the coordinates of all inbetween points. No inbetween points have the same x coordinate and the x coordinate of each inbetween point is less than that of the destination.
5
6 5
1 1
2 3
3 2
4 4
5 3
I have an implementation of the problem in the programming language C++ but the problem is I can't understand it. I've gone through it step by step but I can't understand what it does.
#include <fstream>
#include <cmath>
#include <algorithm>
#include <limits>
using namespace std;
const double inf = numeric_limits<double>::max(); // an infinite number
double dist [205][205] = {0};
double res [205][205] = {0};
int N (0);
struct point {
double x,y;
point(int a,int b):x(a),y(b){}
point(){}
}points[205]; //struct to store inbetween points
inline const bool operator < ( const point &a, const point &b ){
return a.x < b.x;
}
int main()
{
ifstream in ("evripos.in");
ofstream out ("evripos.out");
in>>N;
N+=2;
int t1,t2;
points[0]= point(0,0);
// stores all points
for(int i=1;i<N;++i){
in>>t1>>t2;
points[i]=point(t1,t2);
}
in.close();
sort(points,points+N); // sorts all points according to their x coordinate
// creates a 2 dimensional array of the distances between all points
// called dist
for(int i=0;i<N;++i)
for(int j=0;j<N;++j){
dist [i][j]= sqrt( pow(points[i].x-points[j].x,2) + pow(points[i].y-points[j].y,2));;
res[i][j]=inf;
}
// computes the result, using a 2 dimensional array called res
res[0][0]=0;
for(int i=0;i<N;++i)
for(int j=0;j<N;++j){
res[i+1][i] = min (res[i+1][i], res[i][j] + dist[j][i+1]);
res[i+1][j] = min (res[i+1][j], res[i][j] + dist[i][i+1]);
res[i+1][i+1] = min (res[i+1][i+1], res[i][j] + dist[i][i+1] + dist[i+1][j]);
}
out<<round(res[N-1][N-1])<<endl; //stores the end result
out.close();
}
I've found out that it is a dynamic programming problem and as I understand it the whole logic is in here
res[0][0]=0;
for(int i=0;i<N;++i)
for(int j=0;j<N;++j){
res[i+1][i] = min (res[i+1][i], res[i][j] + dist[j][i+1]);
res[i+1][j] = min (res[i+1][j], res[i][j] + dist[i][i+1]);
res[i+1][i+1]= min (res[i+1][i+1], res[i][j] + dist[i][i+1] + dist[i+1][j]);
}
What exactly is the logic behind this? How is this problem solved with dynamic programming?

This is Bitonic tour problem. You have a list of cities, from 0 to N-1, you need to start from city 0, go through each cities once to reach N-1 and from N-1 go back to 0.
In order to solve the problem, we need to change the way we look at it. Imagine there is not one, but two people starting from city 0, each of them will never be at same city (except 0 and N-1) and they all try to reach city N-1. So if we add the path taken by Person one and Person two, we have the answer for the original problem.
So, we have our int [][]res, with res[i][j] means the minimum total distance for Person one is at city i and Person two is at city j. We observe that this line
res[i+1][i] = min (res[i+1][i], res[i][j] + dist[j][i+1]);
means the Person two starting from city j will go to city i + 1. Notice that i + 1 , not i, which will avoid the case when two persons being at same city. (Also notice that the role of i and j can be interchangeable)
Similarly
res[i+1][j] = min (res[i+1][j], res[i][j] + dist[i][i+1]);
means Person one starting from i go to city i + 1.
Finally, assume that the destination is at i + 1, we have
res[i+1][i+1]= min (res[i+1][i+1], res[i][j] + dist[i][i+1] + dist[i+1][j]);
Note: By the way we increase the index from i to i + 1 in the outer for loop, we also guarantee that all city from 0 to i had been reached (by either Person one or two) before city i + 1 has been reached.
So, the answer for the problem will be at res[N-1][N-1]
Hope that's help!

Related

How to count how many valid colourings in a graph?

I attempted this SPOJ problem.
Problem:
AMR10J - Mixing Chemicals
There are N bottles each having a different chemical. For each chemical i, you have determined C[i] which means that mixing chemicals i and C[i] causes an explosion. You have K distinct boxes. In how many ways can you divide the N chemicals into those boxes such that no two chemicals in the same box can cause an explosion together?
INPUT
The first line of input is the number of test cases T. T test cases follow each containing 2 lines.
The first line of each test case contains 2 integers N and K.
The second line of each test case contains N integers, the ith integer denoting the value C[i]. The chemicals are numbered from 0 to N-1.
OUTPUT
For each testcase, output the number of ways modulo 1,000,000,007.
CONSTRAINTS
T <= 50
2 <= N <= 100
2 <= K <= 1000
0 <= C[i] < N
For all i, i != C[i]
SAMPLE INPUT
3
3 3
1 2 0
4 3
1 2 0 0
3 2
1 2 0
SAMPLE OUTPUT
6
12
0
EXPLANATION
In the first test case, we cannot mix any 2 chemicals. Hence, each of the 3 boxes must contain 1 chemical, which leads to 6 ways in total.
In the third test case, we cannot put the 3 chemicals in the 2 boxes satisfying all the 3 conditions.
The summary of the problem, given a set of chemicals and a set of boxes, count how many possible ways to place these chemicals in boxes such that no chemicals will explode.
At first I used brute force method to solve the problem, I recursively place chemicals in boxes and count valid configurations, I got TLE at my first attempt.
Later I learned that the problem can be solved with graph colouring.
I can represent chemicals as vertexes and there'a an edge between chemicals if they cannot be placed each other.
And the set of boxes can be used as vertex colours, all I need to do was to count how many different valid colourings of the graph.
I applyed this concept to solve the problem unfortunately I got TLE again. I don't know how to improve my code, I need help.
code:
#include <bits/stdc++.h>
#define MAXN 100
using namespace std;
const int mod = (int) 1e9 + 7;
int n;
int k;
int ways;
void greedy_coloring(vector<int> adj[], int color[])
{
int u = 0;
for (; u < n; ++u)
if (color[u] == -1)//found first uncolored vertex
break;
if (u == n)//no uncolored vertexex means all vertexes are colored
{
ways = (ways + 1) % mod;
return;
}
bool available[k];
memset(available, true, sizeof(available));
for (int v : adj[u])
if (color[v] != -1)//if the adjacent vertex colored, make its color unavailable
available[color[v]] = false;
for (int c = 0; c < k; ++c)
if (available[c])
{
color[u] = c;
greedy_coloring(adj, color);
color[u] = -1;//don't forgot to reset the color
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int T;
cin >> T;
while (T--)
{
cin >> n >> k;
vector<int> adj[n];
int c[n];
for (int i = 0; i < n; ++i)
{
cin >> c[i];
adj[i].push_back(c[i]);
adj[c[i]].push_back(i);
}
ways = 0;
int color[n];
memset(color, -1, sizeof(color));
greedy_coloring(adj, color);
cout << ways << "\n";
}
return 0;
}
Counting the number of colorings in a general graph is #P-hard, but this graph has some special structure, which I'll exploit in a minute after I enumerate some basic properties of counting colorings. The first observation is that, if the graph has a node with no neighbors, if we delete that node, the number of colorings decreases by a factor of k. The second observation is that, if a node has exactly one neighbor and we delete it, the number of colorings decreases by a factor of k-1. The third is that the number of colorings is equal to the product of the number of colorings for each connected component. The fourth is that we can delete all but one parallel edge.
Using these properties, it suffices to determine a formula for each connected component of the 2-core of this graph, which is a simple cycle of some length. Let P(n) and C(n) be the number of ways to color a path or cycle respectively with n nodes. We use the basic properties above to find
P(n) = k (k-1)^(n-1).
Finding a formula for C(n) I think requires the deletion contraction formula, which leads to a recurrence
C(3) = k (k-1) (k-2), i.e., three nodes of different colors;
C(n) = P(n) - C(n-1) = k (k-1)^(n-1) - C(n-1).
Multiply the above recurrence by (-1)^n.
(-1)^3 C(3) = -k (k-1) (k-2)
(-1)^n C(n) = (-1)^n k (k-1)^(n-1) - (-1)^n C(n-1)
= (-1)^n k (k-1)^(n-1) + (-1)^(n-1) C(n-1)
(-1)^n C(n) - (-1)^(n-1) C(n-1) = (-1)^n k (k-1)^(n-1)
Let D(n) = (-1)^n C(n).
D(3) = -k (k-1) (k-2)
D(n) - D(n-1) = (-1)^n k (k-1)^(n-1)
Now we can write D(n) as a telescoping sum:
D(n) = [sum_{i=4}^n (D(n) - D(n-1))] + D(3)
D(n) = [sum_{i=4}^n (-1)^n k (k-1)^(n-1)] - k (k-1) (k-2).
Break it down as two geometric sums which then cancel nicely.
D(n) = [sum_{i=4}^n (-1)^n ((k-1) + 1) (k-1)^(n-1)] - k (k-1) (k-2)
= sum_{i=4}^n (1-k)^n - sum_{i=4}^n (1-k)^(n-1) - k (k-1) (k-2)
= (1-k)^n - (1-k)^3 - k (k-1) (k-2)
= (1-k)^n - (1 - 3k + 3k^2 - k^3) - (2k - 3k^2 + k^3)
= (1-k)^n - (1-k)
C(n) = (-1)^n (1-k)^n - (-1)^n (1-k)
= (k-1)^n + (-1)^n (k-1).
Note that after removing all parallel edges, we can have at most n edges. This means that in any one connected component we can only see one cycle (and simple at that), which makes the combinatorics rather straightforward. (Cycles are only dependent on how many edges each node can spawn, which is capped at 1.)
Second example:
k = 3
<< 0 <-- 3
/ ^
/ ^
1 --> 2
Since cycles are self contained, any connection to one removes the possibility of another. In the example above, we cannot make a second cycle involving node 3 by adding more nodes, and the same issue would extend to any subsequent connected nodes.
It should be enough, therefore, to perform a search, separating out connected components and marking their node count and whether they contain a cycle. Given a connected component, where c of the nodes are part of a cycle and m nodes are not, we have the following formula (David Eisenstat helped me correct my combinatoric for the count of colourings of a cycle):
if the component has a cycle:
[(k - 1)^c + (-1)^c * (k - 1)] *
(k - 1)^(m)
otherwise:
k * (k - 1)^(m - 1)
As David Eisenstat noted, multiply all these results for the final tally.

Dynamic programming state calculations

Question:
Fox Ciel is writing an AI for the game Starcraft and she needs your help.
In Starcraft, one of the available units is a mutalisk. Mutalisks are very useful for harassing Terran bases. Fox Ciel has one mutalisk. The enemy base contains one or more Space Construction Vehicles (SCVs). Each SCV has some amount of hit points.
When the mutalisk attacks, it can target up to three different SCVs.
The first targeted SCV will lose 9 hit points.
The second targeted SCV (if any) will lose 3 hit points.
The third targeted SCV (if any) will lose 1 hit point.
If the hit points of a SCV drop to 0 or lower, the SCV is destroyed. Note that you may not target the same SCV twice in the same attack.
You are given a int[] HP containing the current hit points of your enemy's SCVs. Return the smallest number of attacks in which you can destroy all these SCVs.
Constraints-
- x will contain between 1 and 3 elements, inclusive.
- Each element in x will be between 1 and 60, inclusive.
And the solution is:
int minimalAttacks(vector<int> x)
{
int dist[61][61][61];
memset(dist, -1, sizeof(dist));
dist[0][0][0] = 0;
for (int total = 1; total <= 180; total++) {
for (int i = 0; i <= 60 && i <= total; i++) {
for (int j = max(0, total - i - 60); j <= 60 && i + j <= total; j++) {
// j >= max(0, total - i - 60) ensures that k <= 60
int k = total - (i + j);
int & res = dist[i][j][k];
res = 1000000;
// one way to avoid doing repetitive work in enumerating
// all options is to use c++'s next_permutation,
// we first createa vector:
vector<int> curr = {i,j,k};
sort(curr.begin(), curr.end()); //needs to be sorted
// which will be permuted
do {
int ni = max(0, curr[0] - 9);
int nj = max(0, curr[1] - 3);
int nk = max(0, curr[2] - 1);
res = std::min(res, 1 + dist[ni][nj][nk] );
} while (next_permutation(curr.begin(), curr.end()) );
}
}
}
// get the case's respective hitpoints:
while (x.size() < 3) {
x.push_back(0); // add zeros for missing SCVs
}
int a = x[0], b = x[1], c = x[2];
return dist[a][b][c];
}
As far as i understand, this solution calculates all possible state's best outcome first then simply match the queried position and displays the result. But I dont understand the way this code is written. I can see that nowhere dist[i][j][k] value is edited. By default its -1. So how come when i query any dist[i][j][k] I get a different value?.
Can someone explain me the code please?
Thank you!

Euclidean distance between each record with other records in an array

so i have an array [nm] and i need to code in c++ the Euclidean distance between each row and the other rows in the array and store it in a new distance-array [nn] which every cell's value is the distance between the intersected rows.
distance-array:
r0 r1 .....rn
r0 0
r1 0
. 0
. 0
rn 0
the Euclidean distance between tow rows or tow records is:
assume we have these tow records:
r0: 1 8 7
r1: 2 5 3
r2
.
.
rn
Euclidean distance between r0 and r1 = sqrt((1-2)^2+(8-5)^2+(7-3)^2)
to code this i used 4 loops(which i think is too much) but i couldn't do it right, can someone help me to code this without using 3-D array ??
this is my code:
int norarr1[row][column] = { 1,1,1,2,2,2,3,3,3 };
int i = 0; int j = 0; int k = 0; int l = 0;
for (i = 0; i < column; i++){
for(j = 0; j < column; j++){
sumd = 0;
for (k = 0; k < row; k++) {
for (l = 0; l < row; l++) {
dist = sqrt((norarr1[i][k] - norarr1[j][l]) ^ 2);
sumd = sumd + dist;
cout << "sumd =" << sumd << " ";
}
cout << endl;
}
disarr[j][i] = sumd;
disarr[i][j] = sumd;
cout << disarr[i][j];
}
cout << endl;
}
There are several problems with your code. For now, let's ignore the for loops. We'll get to that later.
The first thing is that ^ is the bitwise exclusive or (XOR) operator. It does not do exponentiation like in some other languages. Instead, you need to use std::pow().
Second, you are summing square roots, which is not the correct way to calculate Euclidean distance. Instead, you need to calculate a sum and then take the square root.
Now let's think about the for loops. Assume that you already know which two rows you want to calculate the distance between. Call these r1 and r2. Now you just need to pair one coordinate from r1 with one coordinate from r2. Note that these coordinates will always be in the same column. This means that you only need one loop to calculate the squares of the differences of each pair of coordinates. Then you sum these squares. Finally after this single loop you take the square root.
With that out of the way, we need to iterate over the rows to choose each r1 and r2. Okay, this will take two loops since we want each of these to take on the value of each row.
In total, we will need three for loops. You can make this easier to understand by designing your code well. For example, you can create a class or struct that holds each row. If you know that every row is only three dimensions, then create a point or vector3 class. Now you can write a function which calculates the distance between two points. Finally, store the list of points as a 1D array. In fact, breaking up the data and calculation in this way makes the previous discussion about calculating the distance even easier to understand.

Find two integers such that their product is close to a given real

I'm looking for an algorithm to find two integer values x,y such that their product is as close as possible to a given double k while their difference is low.
Example: The area of a rectangle is k=21.5 and I want to find the edges length of that rectangle with the constraint that they must be integer, in this case some of the possible solutions are (excluding permutations) (x=4,y=5),(x=3,y=7) and the stupid solution (x=21,y=1)
In fact for the (3,7) couple we have the same difference as for the (21,1) couple
21.5-3*7=0.5 = 21.5-21*1
while for the (4,5) couple
21.5-4*5=1.5
but the couple (4,5) is preferable because their difference is 1, so the rectangle is "more squared".
Is there a method to extract those x,y values for which the difference is minimal and the difference of their product to k is also minimal?
You have to look around square root of the number in question. For 21.5 sqrt(21.5) = 4.6368 and indeed the numbers you found are just around this value.
You want to minimize
the difference of the factors X and Y
the difference of the product X × Y and P.
You have provided an example where these objectives contradict each other. 3 × 7 is closer to 21 than 4 × 5, but the latter factors are more square. Thus, there cannot be any algorithm which minimizes both at the same time.
You can weight the two objectives and transform them into one, and then solve the problem via non-linear integer programming:
min c × |X × Y - P| + d × |X – Y|
subject to X, Y ∈ ℤ
X, Y ≥ 0
where c, d are non-negative numbers that define which objective you value how much.
Take the square root, floor one integer, ceil the other.
#include <iostream>
#include <cmath>
int main(){
double real_value = 21.5;
int sign = real_value > 0 ? 1 : -1;
int x = std::floor(std::sqrt(std::abs(real_value)));
int y = std::ceil(std::sqrt(std::abs(real_value)));
x *= sign;
std::cout << x << "*" << y << "=" << (x*y) << " ~~ " << real_value << "\n";
return 0;
}
Note that this approach only gives you a good distance between x and y, for example if real_value = 10 then x=3 and y=4, but the product is 12. If you want to achieve a better distance between the product and the real value you have to adjust the integers and increase their difference.
double best = DBL_MAX;
int a, b;
for (int i = 1; i <= sqrt(k); i++)
{
int j = round(k/i);
double d = abs(k - i*j);
if (d < best)
{
best = d;
a = i;
b = j;
}
}
Let given double be K.
Take floor of K, let it be F.
Take 2 integer arrays of size F*F. Let they be Ar1, Ar2.
Run loop like this
int z = 0 ;
for ( int i = 1 ; i <= F ; ++i )
{
for ( int j = 1 ; j <= F ; ++j )
{
Ar1[z] = i * j ;
Ar2[z] = i - j ;
++ z ;
}
}
You got the difference/product pairs for all the possible numbers now. Now assign some 'Priority value' for product being close to value K and some other to the smaller difference. Now traverse these arrays from 0 to F*F and find the pair you required by checking your condition.
For eg. Let being closer to K has priority 1 and being smaller in difference has priority .5. Consider another Array Ar3 of size F*F. Then,
for ( int i = 0 ; i <= F*F ; ++i )
{
Ar3[i] = (Ar1[i] - K)* 1 + (Ar2[i] * .5) ;
}
Traverse Ar3 to find the greatest value, that will be the pair you are looking for.

minimal cost sum

i want to to calculate minimum sum in given two dimensional array
#include<iostream>
#include<limits.h>
using namespace std;
#define R 3
#define C 3
int Min(int x,int y,int z){
if(x<y){
return (x<z)?x:z;
}
else
return (y<z)?y:z;
}
int mincost(int cost[R][C],int m,int n){
int i,j;
int t[R][C];
t[0][0]=cost[0][0];
for(i=1;i<=m;i++)
t[i][0]=t[i-1][0]+cost[i][0];
for(j=1;j<=n;j++)
t[0][j]=t[0][j-1]+cost[0][j];
for(i=1;i<=m;i++){
for(j=1;j<=n;j++){
t[i][j]=Min(t[i-1][j-1],t[i-1][j],t[i][j-1]+cost[i][j]);
}
}
return t[m][n];
}
int main(){
int cost[R][C]={{1,2,3},
{4,8,2},
{1,5,3}};
cout<<mincost(cost,2,2)<<endl;
return 0;
}
from starting point (0,0) to some point (m,n) for this array it equals 8,but output shows me 1,why?what is wrong with this code?
algorithm in words
Given a cost matrix cost[][] and a position (m, n) in cost[][], write a function that returns cost of minimum cost path to reach (m, n) from (0, 0). Each cell of the matrix represents a cost to traverse through that cell. Total cost of a path to reach (m, n) is sum of all the costs on that path (including both source and destination). You can only traverse down, right and diagonally lower cells from a given cell, i.e., from a given cell (i, j), cells (i+1, j), (i, j+1) and (i+1, j+1) can be traversed. You may assume that all costs are positive integers.
I see that this is a dynamic programming solution.
you have a typo here:
t[i][j]=Min(t[i-1][j-1],t[i-1][j],t[i][j-1]+cost[i][j]);
it should be:
t[i][j]=Min(t[i-1][j-1],t[i-1][j],t[i][j-1]) + cost[i][j];
basically it worked like t[i][j] = t[i-1][j-1].
Note: A good way to debug these problems is to print the intermediate matrix (here: t).
Given that t[0][0] = cost[0][0] = 1
then
for(i=1;i<=m;i++){
for(j=1;j<=n;j++){
t[i][j]=Min(t[i-1][j-1],t[i-1][j],t[i][j-1]+cost[i][j]);
}
for i=1, j=1
t[1][1] = Min(t[0][0], t[0][1], t[1][0]+cost[1][1]) = Min(1, ...) = 1
for i=2 j=2
t[2][2] = Min(t[1][1], t[1][2], t[2][1]+cost[2][2]) = Min(1, ...) = 1
Min(t[i-1][j-1],t[i-1][j],t[i][j-1]+cost[i][j])
should probably be
Min(t[i-1][j-1],t[i-1][j],t[i][j-1]) +cost[i][j]
Just guessing, it's hard to read your intent, but looks like a pathfinding algorithm. Your code wasn't adding the cost properly to diagonal or horizontal movement, and since the cost of the beginning was one, that was also your result. This should return a cost of eleven for your sample.