home *** CD-ROM | disk | FTP | other *** search
- /*******************************************************************************
- +
- + LEDA 2.1.1 11-15-1991
- +
- +
- + _planar.c
- +
- +
- + Copyright (c) 1991 by Max-Planck-Institut fuer Informatik
- + Im Stadtwald, 6600 Saarbruecken, FRG
- + All rights reserved.
- +
- *******************************************************************************/
-
-
-
- /*******************************************************************************
- * *
- * PLANAR (planarity test) *
- * *
- *******************************************************************************/
-
-
- #include <LEDA/graph_alg.h>
- #include <LEDA/node_set.h>
- #include <LEDA/array.h>
-
- declare(list,int)
-
- struct edge_info
- {
- edge e;
- char plaz;
- int seg_nr;
- int block_nr;
-
- OPERATOR_NEW(4)
- OPERATOR_DEL(4)
-
- };
-
-
- struct block
- {
- list(int) L;
- list(int) R;
-
- OPERATOR_NEW(10)
- OPERATOR_DEL(10)
-
- };
-
-
- typedef edge_info* ed_inf;
- typedef block* blptr;
-
- declare(list,ed_inf)
- declare(list,blptr)
-
- typedef list(ed_inf)* lsthead;
-
- declare(array,lsthead)
- declare(array,node)
-
- void swap_plaz( ed_inf& p )
- {
- switch( p->plaz )
- {
- case 'L' : p->plaz = 'R'; break;
- case 'R' : p->plaz = 'L'; break;
- case '=' : p->plaz = '!'; break;
- case '!' : p->plaz = '='; break;
- }
- }
-
-
-
- void mirror( array(lsthead)& segment, int s_nr)
- {
- int i = 1;
- ed_inf x;
-
-
- forall( x, *(segment[s_nr]))
- if( i++ == 1 )
- swap_plaz( x );
- else if( x->seg_nr > s_nr )
- mirror(segment, x->seg_nr);
-
- }
-
-
-
-
- void flipping( array(lsthead)& segment, int s_nr, int h)
- {
- ed_inf x;
-
- forall( x, *(segment[s_nr]))
- {
- if( x->block_nr == h )
- {
- swap_plaz( x );
- if( x->seg_nr > s_nr )
- mirror(segment, x->seg_nr );
- }
- }
-
- }
-
-
- void null_block( lsthead& s, int h)
- {
- ed_inf x;
-
- forall( x, *s)
- if( x->block_nr == h )
- x->block_nr = 0;
-
- }
-
-
- void upd_block_ctr( lsthead& s, int h)
- {
- ed_inf x;
-
- forall( x, *s)
- if( x->block_nr > h )
- x->block_nr = h;
-
- }
-
-
-
-
- void init_segm( array(lsthead)& segment, int cur_nr, edge e)
- {
- ed_inf neu = new edge_info;
-
- neu->e = e;
- neu->block_nr = 0;
- neu->seg_nr = cur_nr;
- neu->plaz = 'L';
-
- (*segment[cur_nr]).push(neu);
- }
-
- void add_edge( lsthead& s, int s_nr, int h, edge e)
- {
- ed_inf neu = new edge_info;
-
- neu->e = e;
- neu->block_nr = h;
- neu->seg_nr = s_nr;
- neu->plaz = '=';
-
- (*s).append(neu);
- }
-
-
-
-
-
-
- int max_L_R(blptr& top)
- {
- int lmax, rmax;
-
- lmax = rmax = 0;
-
- if( !(top->L).empty() )
- lmax = (top->L).head();
- if(!(top->R).empty() )
- rmax = (top->R).head();
-
- return( Max(lmax,rmax) );
- }
-
-
-
-
- void swap_at(blptr& top)
- {
- list(int) tmp = top->L;
-
- top->L = top->R;
- top->R = tmp;
- }
-
-
- int bipartite_test(list(blptr)& atblock, list(int)& A, int k,
- array(lsthead)& segment, int seg_nr)
- {
- int min_att;
- list_item top = atblock.first();
-
- min_att = A.tail();
- while( top && max_L_R(atblock[top]) > min_att )
- {
- if( !atblock[top]->L.empty() && atblock[top]->L.head() > min_att )
- {
- //printf("vor swap %d %d %d\n",atblock[top]->L.head(),k,seg_nr);
- flipping(segment, seg_nr, k-1 );
- swap_at( atblock[top] );
- if( !atblock[top]->L.empty() && atblock[top]->L.head() > min_att )
- return( -1 );
- }
- k--;
- top = atblock.succ(top);
- }
- return( k-1 );
- }
-
-
-
-
- void update_block_stack(list(blptr)& atblock, int h,int dist,
- list(int)& A)
- {
-
- int i;
-
- list(int) ALB, ARB;
-
- for(i=h; i > dist; i--)
- { list_item j = atblock.first();
- ALB = ALB + ((atblock[j])->L);
- ARB = ARB + ((atblock[j])->R);
- atblock.pop();
- }
- blptr neu = new block;
- neu->L = (A + ALB);
- neu->R = ARB;
- atblock.push(neu);
- }
-
- void remove_node_below(int j,int sp_start,int wr,
- list(blptr)& atblock, lsthead& s)
- {
- int h;
- if( j == sp_start)
- j = wr;
- else --j;
-
- list_item top = atblock.first();
-
- while( top && ( !(atblock[top]->L).empty() && atblock[top]->L.head() == j
- || !(atblock[top]->R).empty() && atblock[top]->R.head() == j ) )
- {
- if( !(atblock[top]->L).empty() && atblock[top]->L.head() == j)
- atblock[top]->L.pop();
-
- if( !(atblock[top]->R).empty() && atblock[top]->R.head() == j)
- atblock[top]->R.pop();
-
- if( atblock[top]->L.empty() && atblock[top]->R.empty() )
- {
- h = atblock.length();
- atblock.pop();
- top = atblock.first();
- null_block( s, h);
- }
-
- }
-
- }
-
-
- int strongly_planar(list(blptr)& atblock, int w0, list(int)& A,
- array(lsthead)& segment, int seg_nr)
- {
- int h;
- A.clear();
-
- h = atblock.length();
- while ( !atblock.empty())
- {
- list_item top = atblock.first();
- if( !atblock[top]->R.empty() && atblock[top]->R.head() > w0 )
- {
- swap_at( atblock[top] );
- flipping(segment, seg_nr, h);
- if( !atblock[top]->R.empty() && atblock[top]->R.head() > w0 )
- return( false );
- }
-
- A = A + atblock[top]->L + atblock[top]->R;
- atblock.pop();
- h--;
- }
-
- A += w0;
- return( true );
-
- }
-
-
-
-
-
-
-
- list(int) plantest(array(node)& Graph_order,
- node_array(int)& Dfsnr, edge e,
- array(lsthead)& segment, int& seg_nr)
- {
- int i,j, wr = 0, w0, h, dist, sp_start, sp_end, start_nr, cur_nr;
- node v, w, spine_node;
- edge seg_start;
-
- list(int) A;
- list(blptr) atblock;
-
- spine_node = target(e); // target(e) ist 1. Knoten des Spines zu S(e)
-
- sp_start = Dfsnr[spine_node];
-
- if( sp_start > 1 ) // wr ist der Knoten, an dem S(e) den Stamm verlaesst
- wr = Dfsnr[source(e)];
-
- // finde den Spine: laufe ueber T-Kanten bis zur 1. B-Kante
-
- forall_adj_edges(e,spine_node)
- if( Dfsnr[target(e)] > Dfsnr[spine_node] ) // e ist T-Kante
- spine_node = target(e);
- else break;
-
- sp_end = Dfsnr[source(e)]; // e ist die Basiskante von S(e)
- w0 = Dfsnr[target(e)]; // w0 ist die Basisbefestigung am Stamm
- cur_nr = seg_nr;
- init_segm( segment, cur_nr, e);
-
-
- for(j = sp_end; j >= sp_start; j--)
- {
- v = Graph_order[j]; // v ist der Knoten mit dfsnum j
-
- i = 1;
- forall_adj_edges(seg_start,v) // betr. alle v verlassenden Kanten ausser
- // der ersten Kante
- {
- start_nr = cur_nr;
- if( i++ > 1)
- {
- w = target(seg_start);
-
- if( Dfsnr[w] > Dfsnr[v] ) // Segment startet mit T-Kante
- { // teste S(seg_start)
- start_nr = ++seg_nr;
-
- A = plantest(Graph_order, Dfsnr, seg_start, segment, seg_nr);
-
- if( A.empty() )
- return( A ); // wenn A leer: nicht planar
- }
- else
- A = Dfsnr[w]; // Segment besteht nur aus einer B-Kante
-
- h = atblock.length(); // Anzahl der Eintraege im Blockstack
- // teste, ob Graph noch bipartit, dist liefert Anzahl der zu
- // verschraenkenden Bloecke
-
- if((dist=bipartite_test(atblock,A,h+1,segment,cur_nr)) == -1 )
- { A.clear();
- return( A );
- }
-
- /* aktualisiere die Liste der Bloecke, evtl. werden Bloecke mit
- der Liste A zu einem neuen Block verschmolzen */
-
- update_block_stack(atblock, h, dist, A);
-
- h = atblock.length(); // Anzahl der Eintraege im Blockstack
-
- upd_block_ctr(segment[cur_nr], h);
-
- add_edge(segment[cur_nr],start_nr,h,seg_start);
- }
- }
- /* alle wj verlassenden Kanten sind betrachtet, entferne nun
- alle Befestigungen parent( wj ) */
-
- remove_node_below(j,sp_start, wr, atblock,segment[cur_nr]);
- }
-
- /* teste, ob S(e) stark planar */
- if( ! strongly_planar(atblock, w0, A,segment,cur_nr))
- A.clear();
-
- null_block(segment[cur_nr],1);
-
- //forall(k,A)
- //printf("%d ",k);
- //getchar();
- return ( A ); // liefere Liste der Attachments ab
-
- }
-
-
-
-
-
-
-
-
- int edge_cost(int vnum, int wnum, int l1, int l2)
- {
- if( wnum < vnum )
- return( 2*wnum );
- else if ( l2 >= vnum)
- return( 2*l1 );
- else return ( 2*l1 + 1 );
- }
-
- void bucket_s ( graph& G, int node_anz,
- node_array(int)& Dfsnr,
- node_array(int)& low1,
- node_array(int)& low2 )
- {
- node v,w;
- list(edge)* bucket = new list(edge) [2*node_anz + 1];
- edge e;
- int j, cost_ind;
-
- forall_nodes(v,G)
- {
- forall_adj_edges(e,v)
- {
- w = target(e);
- cost_ind = edge_cost(Dfsnr[v],Dfsnr[w],low1[w],low2[w]);
- bucket[cost_ind].push(e);
- }
- }
- G.del_all_edges();
- for(j=1; j <= 2*node_anz; j++)
- forall(e,bucket[j])
- {
- v = source(e);
- w = target(e);
- G.new_edge(v,w,0);
- }
-
- }
-
-
-
-
-
-
-
-
-
-
- void low(list(edge)& DEL, node v, node prep,
- int& cur_nr, node_set& reached,node_array(int)& Dfsnr,
- node_array(int)& low1, node_array(int)& low2)
- {
- node w;
- edge e;
- int tcan1, tcan2, bcan1, bcan2;
-
- Dfsnr[v] = ++ cur_nr;
- tcan1 = tcan2 = bcan1 = bcan2 = Dfsnr[v];
- reached.insert(v);
- forall_adj_edges(e,v)
- {
- w = target(e);
- if( !reached.member(w) )
- {
- low(DEL,w,v,cur_nr,reached,Dfsnr,low1,low2);
- if( low1[w] < tcan1 )
- {
- tcan2 = tcan1;
- tcan1 = low1[w];
- }
- else if( low1[w] < tcan2 )
- tcan2 = low1[w];
- }
- else if(( Dfsnr[w] >= Dfsnr[v]) || w == prep )
- DEL.append(e) ;
- else if( Dfsnr[w] < bcan1 )
- { bcan2=bcan1;
- bcan1 = Dfsnr[w];
- }
- else if( Dfsnr[w] < bcan2)
- bcan2 = Dfsnr[w];
- }
-
-
- low1[v] = Min(tcan1,bcan1);
- if( tcan1 == bcan1)
- low2[v] = Min(tcan2,bcan2);
- else if ( tcan1 < bcan1)
- low2[v] = Min(bcan1,tcan2);
- else low2[v] = Min(tcan1,bcan2);
-
- }
-
-
- void lowstart(graph& G,node_array(int)& Dfsnr,node_array(int)& low1,
- node_array(int)& low2)
- {
- node v;
- node_set reached(G);
- int cur_nr = 0;
- list(edge) DEL;
- edge e;
-
- G.reset();
- forall_nodes(v,G)
- {
- if( !reached.member(v) )
- low(DEL,v,v,cur_nr,reached,Dfsnr,low1,low2);
- }
- G.reset();
- forall(e,DEL)
- G.del_edge(e);
- }
-
-
- void dfs( node v,
- int& cur_nr, node_set& reached,node_array(int)& Dfsnr)
- {
- node w;
-
- Dfsnr[v] = ++ cur_nr;
- reached.insert(v);
- forall_adj_nodes(w,v)
- if( !reached.member(w) )
- dfs(w,cur_nr,reached,Dfsnr);
-
- }
-
- void dfsstart(graph& G,node_array(int)& Dfsnr)
- {
- node v;
- node_set reached(G);
- int cur_nr = 0;
-
- G.reset();
- forall_nodes(v,G)
- if( !reached.member(v) )
- dfs(v,cur_nr,reached,Dfsnr);
- G.reset();
- }
-
-
-
- void cycl_embedding(graph& G,graph& Comb_Gr, array(node)& Comb_ord, array(node)& Graph_ord,
- node_array(int)& Dfsnr, node_array(int)& Comb_D_nr,
- edge_array(int)& alpha, edge e, edge& grenze)
- {
- node v, w, spine_node;
- edge active, x, seg_start, fst, Lcur, Rcur;
- list(edge) Comb_List, Gr_List;
- int i, j, k, wr, w0, sp_start, sp_end, pos;
-
- if( source(e) != Graph_ord[0] )
- wr = Dfsnr[source(e)];
- else wr = 0;
-
- sp_start = Dfsnr[target(e)];
- pos = alpha[e];
- spine_node = target(e);
-
- if( wr < sp_start )
- {
- forall_adj_edges(e,spine_node)
- if( Dfsnr[target(e)] > Dfsnr[spine_node] ) // e ist T-Kante
- spine_node = target(e);
- else break;
- }
-
- sp_end = Dfsnr[source(e)]; // e ist die Basiskante von S(e)
- w0 = Dfsnr[target(e)]; // w0 ist die Basisbefestigung am Stamm
-
- //printf(" wr %d start %d end %d w0 %d\n",wr,sp_start,sp_end,w0);
-
- for(i= sp_start; i > wr && i < sp_end; i++)
- {
- v = Comb_ord[i];
- if( i > 1 )
- {
- if( i == sp_start )
- w = Comb_ord[wr];
- else w = Comb_ord[i-1];
-
- Comb_Gr.new_edge(v,w);
- }
-
- Comb_Gr.new_edge(v,Comb_ord[i+1]);
- }
-
- //Comb_Gr.print();
- //getchar();
- if( wr < sp_start )
- {
- if(sp_end == sp_start)
- w = Comb_ord[wr];
- else
- w = Comb_ord[sp_end -1];
-
- Comb_Gr.new_edge(Comb_ord[sp_end], w);
-
- if( wr > 0 )
- {
- v = Comb_ord[wr];
- if( pos == 'L')
- {
- fst = Comb_Gr.first_adj_edge(v);
- Comb_Gr.new_edge(fst,Comb_ord[sp_start],0,after);
- }
- else Comb_Gr.new_edge(v,Comb_ord[sp_start]);
- }
- }
-
-
- v = Comb_ord[sp_end];
- if( pos == 'L')
- {
- fst = Comb_Gr.first_adj_edge(v);
- Comb_Gr.new_edge(fst,Comb_ord[w0],0,after);
- }
- else Comb_Gr.new_edge(v,Comb_ord[w0]);
- //Comb_Gr.print();
- //getchar();
- v = Comb_ord[w0];
- Comb_List = Comb_Gr.adj_edges(v);
-
- if( wr > 0 )
- {
- w = Graph_ord[w0];
- Gr_List = G.adj_edges(w);
-
- //printf(" sg %d tg %d\n",Comb_D_nr[source(grenze)],Comb_D_nr[target(grenze)]);
- k = 0;
- forall(x, Gr_List)
- if( Dfsnr[target(x)] > k && Dfsnr[target(x)] <= wr)
- { active = x;
- k = Dfsnr[target(x)];
- }
- forall(x,Comb_List)
- if(Comb_D_nr[target(x)] == Dfsnr[target(active)])
- break;
- active = x;
- }
- else active = Comb_List.head();
-
- //printf(" sa %d ta %d\n",Comb_D_nr[source(active)],Comb_D_nr[target(active)]);
- if( w0 != Comb_D_nr[source(grenze)] )
- {
- if( pos == 'L' )
- x = Comb_Gr.new_edge(active,Comb_ord[sp_end],0,before);
- else
- x = Comb_Gr.new_edge(active,Comb_ord[sp_end],0,after);
- }
- else if ( pos == 'R' )
- x = Comb_Gr.new_edge(grenze,Comb_ord[sp_end],0,before);
- else
- x = Comb_Gr.new_edge(grenze,Comb_ord[sp_end],0,after);
-
- Lcur = Rcur = x;
-
-
- if( wr < sp_start)
- for(j = sp_end; j >= sp_start; j--)
- {
- v = Graph_ord[j];
- i = 1;
- forall_adj_edges(seg_start,v)
- if( i++ > 1)
- {
- if( alpha[seg_start] == 'L' )
- cycl_embedding(G,Comb_Gr,Comb_ord,Graph_ord,Dfsnr,Comb_D_nr,alpha,seg_start,Lcur);
- else
- cycl_embedding(G,Comb_Gr,Comb_ord,Graph_ord,Dfsnr,Comb_D_nr,alpha,seg_start,Rcur);
- }
- }
-
- if( pos == 'R' && Comb_D_nr[source(Rcur)] <= Comb_D_nr[source(grenze)] )
- grenze = Rcur;
- else
- if( pos == 'L' && Comb_D_nr[source(Lcur)] <= Comb_D_nr[source(grenze)] )
- grenze = Lcur;
-
-
- }
-
- /*
- planar( G, Comb) testet den Graphen G auf Planaritaet und berechnet
- die kombinatorische Einbettung von G. Der Graph mit den zyklischen
- Adjazenzlisten wird in Comb zurueckgeliefert.
- Eingabe G : gerichtete Version eines zweifach zusammenhaengenden
- ungerichteten Graphen.
-
- planar() liefert true, falls G planar, sonst false
- */
-
-
-
- int PLANAR( graph& G)
- {
-
- error_handler(0,"PLANAR: sorry, not implemented in this version");
- return false;
-
-
- int i, ed, n=0, seg_num = 0;
- char basis;
- list(int) A;
- node v, w, aux;
- edge e, add_ed, grenze;
- ed_inf x;
-
- graph Comb_Gr;
-
- /*
- G.insert_reverse_edges();
- eliminate_parallel_edges(G);
- */
-
- node_array(int) Dfsnr(G),
- low1(G),
- low2(G);
-
-
- lowstart(G,Dfsnr,low1,low2);
-
- n = G.number_of_nodes();
- ed = G.number_of_edges();
- if( ed > 3*n - 6 )
- { //printf(" no of edges : %d > %d (more than 3*n - 6 edges)\n",ed,3*n - 6);
- return false;
- }
-
- G.reset();
- bucket_s(G,n,Dfsnr,low1,low2);
-
- dfsstart(G,Dfsnr);
-
- w = G.first_node();
- aux = G.new_node();
- add_ed = G.new_edge(aux,w);
-
-
- n++;
- array(lsthead) segment(n);
- for(i =0; i < n; i++)
- segment[i] = new list(ed_inf);
-
-
- array(node) Graph_order(0,n);
- edge_array(int) alpha(G);
- alpha[add_ed] = 'L';
-
-
- forall_nodes(w,G)
- if (w != aux)
- Graph_order[Dfsnr[w]] = w;
- else Graph_order[0] = aux;
-
- A = plantest(Graph_order, Dfsnr, add_ed, segment, seg_num);
-
- if( A.empty() )
- return false;
-
- for(i=0; i <= seg_num ; i++)
- {
- x = (*segment[i]).head();
- basis = x->plaz;
- forall(x, (*segment[i]) )
- {
- e = x->e;
- if( basis == 'L' )
- {
- if ( x->plaz == 'L' || x->plaz == '=')
- alpha[e] = 'L';
- else if( x->plaz == '!')
- alpha[e] = 'R';
- }
- else
- if(x->plaz == 'R' || x->plaz == '=')
- alpha[e] = 'R';
- else alpha[e] = 'L';
- }
- }
-
- list(node) G_Lst, Comb_Lst;
-
- Comb_Gr = G;
- n = Comb_Gr.number_of_nodes();
- node_array(int) Comb_D_nr(Comb_Gr);
- array(node) Comb_ord(0,n);
-
- G_Lst = G.all_nodes();
- Comb_Lst = Comb_Gr.all_nodes();
- list_item topg = G_Lst.first();
- list_item topn = Comb_Lst.first();
- while ( topg != G_Lst.last())
- {
- Comb_D_nr[Comb_Lst[topn]] = Dfsnr[G_Lst[topg]];
- topg = G_Lst.succ(topg);
- topn = Comb_Lst.succ(topn);
- }
- aux = Comb_Lst[topn];
-
- forall_nodes(w,Comb_Gr)
- if( w != aux )
- Comb_ord[Comb_D_nr[w]] = w;
- else Comb_ord[0] = aux;
-
-
-
- v = Comb_ord[2];
- grenze = Comb_Gr.first_adj_edge(v);
-
- Comb_Gr.del_all_edges();
-
- cycl_embedding(G,Comb_Gr,Comb_ord,Graph_order,Dfsnr,Comb_D_nr,alpha,add_ed,grenze);
-
- Comb_Gr.del_node( aux );
-
- G = Comb_Gr;
-
- return true;
-
- }
-