Estimate time complexity of a graph algorithm - algorithm

I have an undirected graph G = (V, E) represented by an adjacency matrix. For each edge I must compute its weakness. The weakness d is computed as follow:
Where Nx is the set of direct nodes of x (with direct nodes I mean the nodes with a path of 1 from x).
I've wrote this algorithm, but I'm not sure about how to evaluate its complexity.
float **graph_weakness(struct graph *g)
{
int i;
int j;
int n = g->n;
struct edge *edge;
int rel_union;
int rel_intersect;
int idx;
float **m = graph_to_matrix(g);
/* complessità: O(|V|/2|E|) */
for (i = 0; i < n; i++) {
edge = g->nodes[i]->edges;
while (edge != NULL) {
idx = edge->idx;
if (m[i][idx] == MATRIX_SET) {
rel_union = 0;
rel_intersect = 0;
for (j = 0; j < n; j++) {
if (m[i][j] != 0.0 || m[idx][j] != 0.0) {
rel_union++;
}
if (m[i][j] != 0.0 && m[idx][j] != 0.0) {
rel_intersect++;
}
}
m[i][idx] = 1 - (float) rel_intersect / rel_union;
m[idx][i] = m[i][idx];
}
edge = edge->next;
}
}
return m;
}
The algorithm iterates over the edges and for each edge computes the intersection and union of the sets using a loop from 1..|V|.
Tha matrix is symmetric so the computation is made on half the edges.
The complexity should therefore be O(|E|/2 * |V|) = O(|E|*|V|), am I right?

The line
float **m = graph_to_matrix(g);
is probably Θ(|V| |E|)
(it depends on your matrix library).
(Perhaps somewhat contrary to the statement in your question), the algorithm starts by looping over all nodes
for (i = 0; i < n; i++) {
For each node, it iterates over all neighbors
while (edge != NULL) {
and for each neighbor, it iterates over all nodes again
for (j = 0; j < n; j++) {
So, assuming your graph has adjacency-list representation, this first + second loop are run O(|E| + |v|) times altogether, and each iteration iterates over |V| items.
This algorithm is O((|E| + |V|) |V|), therefore.

Related

minimum cost to reach destination through tunnels

Recently I faced a problem in the interview and not able to answer it. Any help will be appreciated.
Given a two dimensional grid (1 <= row <= 10^9 && 1 <= col <= 10^9) and starting and ending coordinates. we can only go to the four adjacent cells and it cost 1 unit. we also have N tunnels (1 <= N <= 200) whose starting and ending coordinates are given and if we go through the tunnel it costs k unit (1 <= k <= 10^9).
Note: It is not necessary to take tunnels but if we take one it costs k unit of energy per tunnel taken.
we have to find the minimum cost to reach the destination from the starting coordinate.
starting coordinate (1 <= sx, sy <= 10^9)
destination coordinate (1 <= fx, fy <= 10^9)
The problem needs to be transposed into a graph with a weight given to each vertex. Once we have done that, we can use the Dijkstra algorithm to find the shortest path.
Solving the problem thus boils down to transposing the problem into a graph with weighted vertices.
We can go from any cell to any other cell without going through a tunnel. The cost is then the manhattan distance. When the coordinate of a cell c1 is (x1,y1) and another cell c2 is (x2,y2), the manhattan distance between c1 and c2 is d=abs(x2-x1)+abs(y2-y1).
The nodes of the graph will correspond to the starting cell, the final cell, and every tunnel exit cells. The number of nodes in the graph is 2 + n where n is the number of tunnels.
There is a vertex between every node. The weight of a vertex to the final node is simply the manhattan distance. The weight of a vertex to a tunnel exit node is the manhattan distance to the tunnel entry cell plus the weight k associated to the tunnel.
This yields a graph that we can now solve using the Dijkstra algorithm to find the shortest path.
As chmike mentioned, the question can first be transformed into a graph. Then Djikstra's algorithm for finding shortest paths can be used. Here's is my code -
#include<bits/stdc++.h>
using namespace std;
#define int long long int
const int N = 402;
int dp[N][N];
pair<int,int> g[N];
int dist[N];
bool vis[N];
int32_t main(){
int k,a,b,c,d,n,p,q,r,s,index,nodes,val;
cin>>k>>a>>b>>c>>d>>n;
index = 2;
nodes = 2*n+1;
for(int i=1;i<=nodes;i++)
dist[i] = INT_MAX;
memset(vis,false,sizeof(vis));
memset(dp,-1,sizeof(dp));
for(int i=0;i<=nodes;i++)
dp[i][i] = 0;
g[0] = {a,b};
g[1] = {c,d};
dp[0][1] = dp[1][0] = abs(a-c)+abs(b-d);
for(int i=0;i<n;i++){
cin>>p>>q>>r>>s;
dp[index][index+1] = k;
dp[index+1][index] = k;
g[index] = {p,q};
g[index+1] = {r,s};
for(int j=0;j<index;j++){
val = abs(p-g[j].first)+abs(q-g[j].second);
dp[j][index] = dp[index][j] = val;
val = abs(r-g[j].first)+abs(s-g[j].second);
dp[j][index+1] = dp[index+1][j] = val;
}
index += 2;
}
for(int i=0;i<=nodes;i++){
int v = -1;
for(int j=0;j<=nodes;j++){
if(!vis[j] && (v == -1 || dist[j] < dist[v]))
v = j;
}
if(dist[v] == INT_MAX)
break;
vis[v] = true;
for(int j=0;j<=nodes;j++)
dist[j] = min(dist[j], dist[v]+dp[v][j]);
}
cout<<dist[1];
return 0;
}
you can use dynamic programming
#include <bits/stdc++.h>
using namespace std;
#define type long long
int main()
{ //k i sost of travelling through tunnel
//sx and sy are starting coordinates
//fx and fy are ending coordinates
//n are number of tunnels
int k, sx, sy, fx ,fy,n;
cin>>k>>sx>>sy>>fx>>fy>>n;
vector<vector<int>> arr(n, vector<int>(4,0));
map<pair<int, int> , pair<int,int>> mp;
//taking inputof tunnel elements and storing it in a map
for(int i=0; i<n; i++)
{
for(int j=0; j<4; j++)
cin>>arr[i][j];
pair<int,int> a,b;
a= pair<int,int> (arr[i][0], arr[i][1]);
b= pair<int, int> (arr[i][2], arr[i][3]);
mp[a] = b;
mp[b] =a;
}//cin the elements
//function
vector<vector<type>> dp (fx+1, vector<type>(fy+1,LONG_LONG_MAX));
dp[fx][fy] =0; //end
for(int i= fx; i>=0; i--)
{
for(int j= fy; j>=0; j--)
{
//go down
if(j+1< fy)
{
dp[i][j] = min(dp[i][j] , dp[i][j+1]+1 );
}
//go right
if(i+1< fx)
{
dp[i][j] = min(dp[i][j] , dp[i+1][j]+1 );
}
//tunnel
if(mp.find(pair<int, int> (i,j))!= mp.end())
{
pair<int, int> temp= mp[pair<int, int> (i,j)];
int a= temp.first, b= temp.second;
if(dp[a][b]!= LONG_LONG_MAX)
{
dp[i][j] = min(dp[i][j] , dp[a][b]+ k );
}
}
}
}//
cout<<dp[sx][sy]<<'\n';
}
here i have used dp
the array dp is 2-d matrix that saves the cost to reach fx, fy.
we start from bottom up approach, at each cell we find the minimum cost to reach the end.
we check the cost to reach by stepping 1 cell downward i.e. from dp[i][j] to dp[i][j+1] .
then we check the right cell by dp[i+1][j]
we see if tunnel is present.

Maximum Matching in Graph

I have 2D Array where each element is O or Non Zero, I have to collect all 1 elements. For Doing so I will hire a workers
`0` - dead coconut tree
`Non Zero` - living tree
A worker starts harvesting at a living tree and continues harvesting along a straight line of trees in one of the four cardinal directions (i.e., north, south, east, or west). A worker stops harvesting coconuts when one of the following conditions is satisfied
The worker comes across a dead coconut tree.
The worker hits the edge of the plantation (i.e., there are no more
harvestable trees in that direction).
For Example Array Look Like This:
So Minimum 4 workers are required
Question:
I was shocked when i came to know this is Maximum Matching Problem , i had no idea how is it so.
Following is Code which Mark the Horizontal and Vertical Strips with a index
m=1;
for (int i=0; i<r; i++) {
int j = 0;
while (j < c && a[i][j] < m) j++;
while (j < c) {
while (j < c && a[i][j] >= m) {
h[i][j] = hcnt;
j++;
}
hcnt++;
while (j < c && a[i][j] < m) j++;
}
}
int vcnt = 0;
for (int j=0; j<c; j++) {
int i = 0;
while (i < r && a[i][j] < m) i++;
while (i < r) {
while (i < r && a[i][j] >= m) {
v[i][j] = vcnt;
i++;
}
vcnt++;
while (i < r && a[i][j] < m) i++;
}
}
So my Question is How to add edges and why it's maximum matching problem and can someone explain the intuition behind this why maximum matching works on this problem.
Original Question
Following Code Add the edges. I hade no idea how we are adding the edges and why is it working
int s = 0, t = hcnt + vcnt + 1;
for (int i=0; i<hcnt; i++) addEdge(s, i+1, 1);
for (int i=0; i<r; i++) {
for (int j=0; j<c; j++) if(a[i][j] >= m) {
addEdge(1 + h[i][j], 1 + hcnt + v[i][j], 1);
}
}
for (int i=0; i<vcnt; i++) addEdge(1 + hcnt + i, t, 1);
The idea is as follows: we need to take some vertical and horizontal lines in such a way that all trees are covered and the number of picked lines is minimized.
Each cell with a tree becomes an edge in the graph. Each vertical line becomes a vertex in the left part of the graph and each horizontal line becomes a vertex in the right part. Now the problem is equivalent to finding a vertex cover in this graph. The size of the maximum matching is equal to the size of the vertex cover in any bipartite graph (it's a more or less well-known theorem).

Construct any bipartite graph with degree constraints

We need to construct a bipartite graph with N vertices each, on the two parts, and with total number of edges equal to M.
The vertices on the left are numbered from 1 to N.
The vertices on the right are also numbered from 1 to N.
The degree of every vertex to be greater than or equal to X, and to be lesser than or equal to Y. i.e. for all v, X ≤ deg(v) ≤ Y
Given four integers N, M, X, Y we need to construct some bipartite graph satisfying this property. If there does not exist any such graph, then also tell the same.
Example :
If N=2 , M=3 , X=1 and Y=2
then the 3 edges in bipartite graph will be : (1,1),(2,2) and (1,2)
If N=2 , M=3 , X=1 and Y=1 then no bipartite graph exists.
How can this problem be solved if
1 ≤ N ≤ 100
1 ≤ X ≤ Y ≤ N
0 ≤ M ≤ N * N
Original question link
Obviously, the variables need to satisfy:
X * N <= M <= Y * N
Otherwise, there will be no solution.
Finding the edges could be done in waves. Start by connecting each node i from the first set to the according node i from the second set. In the next wave, connect i with (i + 1) mod N. Then i with (i + 2) mod N and so one. This will increase the degree of each vertex by exactly one in each wave. Stop whenever you have constructed M edges. This may also happen during a wave.
ACM ICPC 2016 India Preliminary Round Problem.
Link
The contest is now ended. I couldn't submit the answer (was about to submit the code just 10 secs before the end and my Internet stopped working).
d is equivalent to X in the OP's version of the problem.
D is equivalent to Y in the OP's version of the problem.
t is the number of test cases.
I made the code as per the original question in the link.
The logic is similar to
Nico Schertler's one. My complexity will be a little more because instead of just connecting, i+xth node to i in the xth iteration, I have used a set that finds the first element not connected in the range [1..N] and connects them.
This is my code:
#include <bits/stdc++.h>
using namespace std;
int main() {
int t, n, m, d, D;
cin >> t;
while(t--) {
cin >> n >> m >> d >> D;
if(n*D < m || n*d > m)
printf("-1\n");
else {
vector <set <int> > v(n);
int edges = 0, count = 0;
while(count != d) {
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if(v[i].find(j) == v[i].end()) {
v[i].insert(j);
++edges;
break;
}
if(edges == m)
break;
}
if(edges == m)
break;
}
++count;
}
while(edges < m) {
for(int i = 0; i < n; i++) {
if(v[i].size() == D)
continue;
for(int j = 0; j < n; j++) {
if(v[i].find(j) == v[i].end()) {
v[i].insert(j);
++edges;
break;
}
if(edges == m)
break;
}
if(edges == m)
break;
}
}
for(int i = 0; i < n; i++) {
set <int>::iterator it = v[i].begin();
for(; it != v[i].end(); ++it) {
printf("%d %d\n", i+1, (*it)+1);
}
}
}
}
return 0;
}
I don't know whether this code is correct or not.

Time Complexity O(V^3) or O(V^2)?

I'm new for analyzing the algorithms and the time for them.. This algorithm is posted in http://geeksforgeeks.com and they wrote that the time complexity of the algorithm is O(V^2) which i think that it's O(V^3):
int minDistance(int dist[], bool sptSet[])
{
// Initialize min value
int min = INT_MAX, min_index;
for (int v = 0; v < V; v++)
if (sptSet[v] == false && dist[v] <= min)
min = dist[v], min_index = v;
return min_index;
}
// A utility function to print the constructed distance array
int printSolution(int dist[], int n)
{
printf("Vertex Distance from Source\n");
for (int i = 0; i < V; i++)
printf("%d \t\t %d\n", i, dist[i]);
}
// Funtion that implements Dijkstra's single source shortest path algorithm
// for a graph represented using adjacency matrix representation
void dijkstra(int graph[V][V], int src)
{
int dist[V]; // The output array. dist[i] will hold the shortest
// distance from src to i
bool sptSet[V]; // sptSet[i] will true if vertex i is included in shortest
// path tree or shortest distance from src to i is finalized
// Initialize all distances as INFINITE and stpSet[] as false
for (int i = 0; i < V; i++)
dist[i] = INT_MAX, sptSet[i] = false;
// Distance of source vertex from itself is always 0
dist[src] = 0;
// Find shortest path for all vertices
for (int count = 0; count < V-1; count++)
{
// Pick the minimum distance vertex from the set of vertices not
// yet processed. u is always equal to src in first iteration.
int u = minDistance(dist, sptSet);
// Mark the picked vertex as processed
sptSet[u] = true;
// Update dist value of the adjacent vertices of the picked vertex.
for (int v = 0; v < V; v++)
// Update dist[v] only if is not in sptSet, there is an edge from
// u to v, and total weight of path from src to v through u is
// smaller than current value of dist[v]
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX
&& dist[u]+graph[u][v] < dist[v])
dist[v] = dist[u] + graph[u][v];
}
// print the constructed distance array
printSolution(dist, V);
}
Where the graph represented inside graph[][] (matrix representation).
Thanks in advance
The solution is indeed O(V^2):
for (int i = 0; i < V; i++)
dist[i] = INT_MAX, sptSet[i] = false;
This part runs BEFORE the main loop, and in complexity of O(V) -.
for (int count = 0; count < V-1; count++)
{
This is the main loop, it runs O(V) times overall, and each time it requires:
int u = minDistance(dist, sptSet);
This runs one time per each different value of count, and its complexity is O(V), so we have O(V^2)` by now.
sptSet[u] = true;
This is O(1), and runs O(V) times.
for (int v = 0; v < V; v++)
This loop runs O(V) times, for each value of count, let's examine what happens each time you run it:
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX
&& dist[u]+graph[u][v] < dist[v])
dist[v] = dist[u] + graph[u][v];
All of those are O(1), and done per each (count,v) pair, and there are O(V^2) of those pairs.
So, totally O(V^2).
Note that for more efficient graph representation, we can run Dijkstra's algorithm in O(E + VlogV), which might be better in case of sparse graphs.

find the largest sub- matrix full of ones in linear time

Given an n by n matrix with zeros and ones, find the largest sub-
matrix full of ones in linear time. I was told that a solution with
O(n) time complexity exists. If there are n^2 elements in a n X n
matrix how does a linear solution exist?
Unless you have a non-standard definition of submatrix this problem is NP-hard by reduction from maximum clique.
You can't search a n x n matrix in n time. Counterexample: a matrix of zeros with a single element set to one. You have to check every element to find where that one is, so time must be at least O(n^2).
Now if you say that the matrix has N = n^2 entries, and you only consider submatrices that form a contiguous block, then you should be able to find the largest submatrix by walking diagonally across the matrix, keeping track of every rectangle of ones as you go. You could in general have up to O(sqrt(N)) rectangles active simultaneously, and you would need to search in them to figure out which rectangle was the largest, so you ought to be able to do this in O(N^(3/2) * log(N)) time.
If you can pick arbitrary rows and columns to form your submatrix, then I don't see any obvious polynomial time algorithm.
The solution is linear in the number of entries, not in the number of rows or columns.
public static int biggestSubMatrix(int[][] matrix) {
int[][] newMatrix = new int[matrix.length][matrix[0].length];
for (int i = 0; i < matrix.length; i++) {
int sum = 0;
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[i][j] == 1) {
sum++;
newMatrix[i][j] = sum;
} else {
sum = 0;
newMatrix[i][j] = 0;
}
}
}
int maxDimention = 0;
int maxSubMatrix = 0;
for (int i = 0; i < newMatrix[0].length; i++) {
//find dimention for each column
maxDimention = calcHighestDimentionBySmallestItem(newMatrix, i);
if(maxSubMatrix < maxDimention ){
maxSubMatrix = maxDimention ;
}
}
return maxSubMatrix;
}
private static int calcHighestDimentionBySmallestItem(int[][] matrix, int col) {
int totalMaxDimention =0;
for (int j = 0; j < matrix.length; j++) {
int maxDimention = matrix[j][col];
int numItems = 0;
int min = matrix[j][col];
int dimention = 0;
for (int i = j; i < matrix.length; i++) {
int val = matrix[i][col];
if (val != 0) {
if (val < min) {
min = val;
}
numItems++;
dimention = numItems*min;
if(dimention>maxDimention){
maxDimention = dimention;
}
} else { //case val == 0
numItems = 0;
min = 0;
}
}
if(totalMaxDimention < maxDimention){
totalMaxDimention = maxDimention;
}
}
return totalMaxDimention;
}

Resources