Given an undirected graph. How do I check if it can be divided into two sets where every node of one set is connected to every other node of its own set (complete graph). A set can be empty or of only one node. No node should be remaining.
Thanks.
EDIT: Edges between two sets is not forbidden.
Basically we have to check if the graph can be divided into two cliques
As commented by #Damien, checking whether vertices of a given graph can be partitioned into two cliques is actually the decision problem of clique cover with k = 2. For general k (even for k = 3), the clique cover problem is known to be NP-complete. For k = 2, there exists a O(n2) algorithm, based on the observation below.
Given a graph G = (V, E), denote its complement as G'. Then V can be partitioned into two cliques if and only if G' is 2-colorable.
The proof is simple and thus omitted here. The sketch of the algorithm is shown below.
01. construct G' from G;
02. if G' is bipartite
03. return true;
04. else
05. return false;
Note that the first line requires O(n2) time, while testing whether G' is bipartite requires only O(n + m) time using BFS, where n is the # of vertices and m is the # of edges. Therefore, the total complexity is O(n2).
Related
so in one of my lectures I came across the proof for:
šš”ššØš«šš¦: š“šš¦ algorithm that determines if a graph is bipartite
that has as its input an undirected graph šŗ = (š, šø) represented
as an š Ć š adjacency matrix, has the running time of Ī©(š^2)
We assume an algorithm ALG which test for bipartiteness (returns either true or false). And we also assume we have a graph šŗ0 = (š, šø0) with š = {1,2, ā¦ , š} and šø0 = { 1, š : 2 ā¤ š ā¤ š} (as this is a star it is a bipartite graph)
Within the proof there's a step saying:
"For a given algorithm ALG, we will construct another graph šŗ1 st: if ALG performs less than (šā1)C2 accesses to the adjacency matrix š“ of šŗ0,
then ALG will not distinguish between šŗ0 and šŗ1, and šŗ1 is not bipartite."
My question is what does (n-1)C2 accesses mean. Is it saying that for example if we have a different V = {A,B,C,D} then ALG will look at all node pairs except for the ones between D and the other nodes ?
Sorry if this isn't clear this proof really confused me.
G0 is an n-vertex star graph. It's bipartite, but if you add any other edge to it, the resulting graph is not. There are nā1 choose 2 = (nā1)(nā2)/2 = Ī©(n2) other edges that we can add. Every correct algorithm must check every single one in order to verify that G0 is bipartite.
Assume we have an undirected Graph G = (V,E) and we construct a new Graph G' where two nodes are adjacent if they have a common neighbor node in G.
Can someone explain why the following statements are true if we have such a construction G'?
If G has an independent set of size n, then G' has a matching of size n.
If G' has an matching of size n, then G has an independent set of size n.
Unfortunately I don't have an idea for this problem
I am working on the following past paper question for an algorithms module:
Let G = (V, E) be a simple directed acyclic graph (DAG).
For a pair of vertices v, u in V, we say v is reachable from u if there is a (directed) path from u to v in G.
(We assume that every vertex is reachable from itself.)
For any vertex v in V, let R(v) be the reachability number of vertex v, which is the number of vertices u in V that are reachable from v.
Design an algorithm which, for a given DAG, G = (V, E), computes the values of R(v) for all vertices v in V.
Provide the analysis of your algorithm (i.e., correctness and running time
analysis).
(Optimally, one should try to design an algorithm running in
O(n + m) time.)
So, far I have the following thoughts:
The following algorithm for finding a topological sort of a DAG might be useful:
TopologicalSort(G)
1. Run DFS on G and compute a DFS-numbering, N // A DFS-numbering is a numbering (starting from 1) of the vertices of G, representing the point at which the DFS-call on a given vertex v finishes.
2. Let the topological sort be the function a(v) = n - N[v] + 1 // n is the number of nodes in G and N[v] is the DFS-number of v.
My second thought is that dynamic programming might be a useful approach, too.
However, I am currently not sure how to combine these two ideas into a solution.
I would appreciate any hints!
EDIT: Unfortunately the approach below is not correct in general. It may count multiple times the nodes that can be reached via multiple paths.
The ideas below are valid if the DAG is a polytree, since this guarantees that there is at most one path between any two nodes.
You can use the following steps:
find all nodes with 0 in-degree (i.e. no incoming edges).
This can be done in O(n + m), e.g. by looping through all edges
and marking those nodes that are the end of any edge. The nodes with 0
in-degree are those which have not been marked.
Start a DFS from each node with 0 in-degree.
After the DFS call for a node ends, we want to have computed for that
node the information of its reachability.
In order to achieve this, we need to add the reachability of the
successors of this node. Some of these values might have already been
computed (if the successor was already visited by DFS), therefore this
is a dynamic programming solution.
The following pseudocode describes the DFS code:
function DFS(node) {
visited[node] = true;
reachability[node] = 1;
for each successor of node {
if (!visited[successor]) {
DFS(successor);
}
reachability[node] += reachability[successor];
}
}
After calling this for all nodes with 0 in-degree, the reachability
array will contain the reachability for all nodes in the graph.
The overall complexity is O(n + m).
I'd suggest using a Breadth First Search approach.
For every node, add all the nodes that are connected to the queue. In addition to that, maintain a separate array for calculating the reachability.
For example, if a A->B, then
1.) Mark A as traversed
2.) B is added to the queue
3.) arr[B]+=1
This way, we can get R(v) for all vertices in O(|V| + |E|) time through arr[].
I'm pretty sure this problem is P and not NP, but I'm having difficulty coming up with a polynomially bound algorithm to solve it.
You can :
check that number of edges in the graph is n(n-1)/2.
check that each vertice is connected to exaclty n-1 distinct vertices.
This will run in O(VĀ²), which is polynomial.
Hope it helped.
Here's an O(|E|) algorithm that also has a small constant.
It's trivial to enumerate every edge in a complete graph. So all you need to do is scan your edge list and verify that every such edge exists.
For each edge (i, j), let f(i, j) = i*|V| + j. Assuming vertices are numbered 0 to |V|-1.
Let bitvec be a bit vector of length |V|2, initialized to 0.
For each edge (i, j), set bitvec[f(i, j)] = 1.
G is a complete graph if and only if every element of bitvec == 1.
This algorithm not only touches E once, but it's also completely vectorizable if you have a scatter instruction. That also means it's trivial to parallelize.
Here is an O(E) algorithm:
Use O(E) as it is input time, to scan the graph
Meanwhile, record each vertex p's degree, increase degree only if the neighbor is not p itself (self-connecting edge) and is not a vertex q where p and q has another edge counted already (multiple edge), these checking can be done in O(1)
Check if all vertex's degree is |V|-1, this step is O(V), if Yes then it is a complete graph
Total is O(E)
For a given graph G = (V,E), check for each pair u, v in the V, and see if edge (u,v) is in E.
The total number of u, v pairs are |V|*(|V|-1)/2. As a result, with a time complexity of O(|V|^2), you can check and see if a graph is complete or not.
We have a Code on Weighted, Acyclic Graph G(V, E) with positive and negative edges. we change the weight of this graph with following code, to give a G without negative edge (G'). if V={1,2...,n} and G_ij be a weight of edge i to edge j.
Change_weight(G)
for t=1 to n
for j=1 to n
G_i=min G_ij for All K
if G_i < 0 (we have a bar on G)
G_ij = G_ij+G_i for all j
G_ki = G_ki+G_i for all k
We have two axioms:
1) the shortest path between every two vertex in G is the same as G'.
2) the length of shortest path between every two vertex in G is the same as G'.
i read one pdf that has low quality, i'm not sure the code exactly mentioned, and add the picture. in this book he say the above axioms is false, anyone could help me? i think these are true?
i think two is false as following counter example, the original graph is given in left, and after the algorithm is run, the result is in right the shortest path between 1 to 3 changed, it passed from vertex 2 but after the algorithm is run it never passed from vertex 2.
Algorithm
My reading of the PDF is:
Change_weight(G)
for i=i to n
for j=1 to n
c_i=min c_ij for all j
if c_i < 0
c_ij = c_ij-c_i for all j
c_ki = c_ki+c_i for all k
The interpretation is that for each vertex we increase its outgoing edges by c_i, and decrease the incoming edges by c_i, where c_i is chosen such that all outgoing edges become non-negative.
Claim 1
"the shortest path between every two vertex in G is the same as G'"
With my reading of the pdf, this claim is true because every path between vertices i and j is changed by the same amount (c_i-c_j) and so the relative order of paths is unchanged. (Note that the path may go via intermediate vertices, but the net effect is 0 because for each intermediate vertex k we decrease the length by c_k when entering, but increase by c_k when exiting.)
Claim 2
"the length of shortest path between every two vertex in G is the same as G'".
This cannot be true - suppose we start with an original graph which has a single edge A to B with weight -1.
In the modified graph this weight will become 0.
Therefore the length of the shortest path has changed from -1 in G to 0 in G' so the statement is false.
Example
Shown below is what would happen to your graph as you applied this algorithm to node 1, followed by node 2:
Topological sort
Note that as shown in the example, we still end up with some negative weights which is probably unintended. This is because the weights of incoming edges are reduced.
However, if we work backwards through the graph (e.g. by using a topological sort), then we will always end up with non-negative weights everywhere.
In the given example, working backwards means we first update 2, and then 1 as shown below: