/** * This program transforms a permutation in an equivalent simple permutation. * For details see the paper: How to achieve an equivalent simple permutation in linear time. * Proceedings of the 5th Annual RECOMB Satellite Workshop on Comparative Genomics, LNCS, 2007. * * Author: Simon Gog, Ulm University, Germany */ #include #include #include #include #include #include using namespace std; const int SHORT_CYCLE = -1; const int UNDEF = -2; const int DONE = -3; const int INTERLEAVE = -4; struct e; typedef struct e { e* desire, *reality, *co_elem; int val, pos, add, overlapp, cycle; e(){ desire=reality=co_elem=NULL; val = 0; pos = 0; cycle = UNDEF; } } elem; void printPerm(vector &perm, int reality=1,int force_nl=1){ elem *e = &perm[0]; e = (reality) ? e->reality : e-> desire; while( e->co_elem != NULL){ printf("%c%d ", (e->val%2==1)?'+':'-', (e->val+1)/2); e = (reality) ? e->co_elem->reality : e->co_elem->desire; } if(force_nl) printf("\n"); } // determine if n1 belongs to a long cycle int is_long_cycle(elem *n1){ if(n1->cycle==SHORT_CYCLE) return 0; elem *nl = n1->reality, *n2 = n1->desire; elem *nl_1 = nl->desire; int res = nl!=n2 && n2->reality!=nl_1; if(!res) n1->cycle = n2->cycle = nl->cycle = nl_1->cycle = SHORT_CYCLE; return res; } // determine if the desire edges of nodes n_x and n_y are interleaving int interleave(elem *n_x, elem *n_y){ if( n_x->pos > n_x->desire->pos ) n_x = n_x->desire; if( n_y->pos > n_y->desire->pos ) n_y = n_y->desire; return (n_x->pos < n_y->pos && n_x->desire->pos > n_y->pos && n_x->desire->pos < n_y->desire->pos) || (n_y->pos < n_x->pos && n_y->desire->pos > n_x->pos && n_y->desire->pos < n_x->desire->pos); } // perform a (b,g)-split void bg_split(elem *b1, elem *b2, elem *g1, elem *g2, int &n, vector &perm, elem *&neu1, elem *&neu2){ ++n; neu1 = &perm[2*n]; neu2 = &perm[2*n+1]; neu1->pos = b2->pos; neu2->pos = b1->pos; if( g1->val % 2 ==0 ){ neu1->val = 2*n-1; neu2->val = 2*n; }else{ neu1->val = 2*n; neu2->val = 2*n-1; } neu1->co_elem = neu2; neu2->co_elem = neu1; b1->reality = neu1; neu1->reality = b1; b2->reality = neu2; neu2->reality = b2; neu1->desire = g1; g1->desire = neu1; neu2->desire = g2; g2->desire = neu2; neu1->cycle = neu1->reality->cycle; neu2->cycle = neu2->reality->cycle; is_long_cycle(neu1); is_long_cycle(neu2); printPerm(perm,1,0); printf(" -> "); printPerm(perm,0); } int markCycles(vector &perm, int cycle_nr=0){ for(elem *n_s=&perm[0]; n_s != NULL; n_s = n_s->reality->co_elem) if(is_long_cycle(n_s) && n_s->cycle == UNDEF){ //mark cycle for(elem *e = n_s; e->cycle == UNDEF; e = e->reality->desire) e->cycle = e->reality->cycle = cycle_nr; ++cycle_nr; } return cycle_nr; } void readPerm(vector &perm, int n){ perm.resize(4*n+2); vector inv_perm(2*n+2); perm[0].reality = &perm[1]; for(int i=0, x=0; i < n; ++i){ cin>>x; perm[2*i+1].reality = &perm[2*i]; perm[2*i+1].co_elem = &perm[2*i+2]; perm[2*i+2].co_elem = &perm[2*i+1]; if( x>0 ){ perm[2*i+1].val = 2*x-1; perm[2*i+2].val = 2*x; } else{ perm[2*i+1].val = 2*(-x); perm[2*i+2].val = 2*(-x)-1; } perm[2*i+2].reality = &perm[2*i+3]; } perm[2*n+1].reality = &perm[2*n]; perm[2*n+1].val = 2*n+1; for(int i=0; i<2*n+2; ++i){ perm[i].pos = i; inv_perm[perm[i].val] = i; } for(int i=0; i<=n; ++i){ perm[inv_perm[2*i]].desire = &perm[inv_perm[2*i+1]]; perm[inv_perm[2*i]].desire->desire = &perm[inv_perm[2*i]]; } } int main(){ int n, org_n, j, cycle_nr; elem *x, *y, *n_s; while(cin>>n && n>0){ vector perm; readPerm(perm, n); org_n = n; printPerm(perm,1,0); printf(" -> "); printPerm(perm,0); cycle_nr = markCycles(perm); vector n_2ip1(cycle_nr, (elem*)NULL), n_1(cycle_nr, (elem*)NULL); // Phase 1 for(n_s = &perm[0]; n_s != NULL; ){ if( (j=n_s->cycle) == SHORT_CYCLE || n_s->cycle == DONE) n_s = n_s->reality->co_elem; else if(n_2ip1[j] == NULL){ // reach leftmost node of cycle C_j n_1[j] = n_s; // store leftmost element of C_j n_2ip1[j] = n_s->reality->desire; n_s = n_s->reality->co_elem; } else if(n_s == n_2ip1[j]){ n_2ip1[j] = n_s->reality->desire; n_s = n_s->reality->co_elem; } else if(n_2ip1[j]->pos%2 == 0){ // g_i unoriented ? bg_split(n_2ip1[j], n_2ip1[j]->reality, n_1[j], n_1[j]->desire, n, perm, x, y); n_2ip1[j]->cycle = x->cycle = DONE; n_2ip1[j] = NULL; // uninitialize leftmost node of cycle C_j } else if(n_1[j]->reality != n_2ip1[j]->desire){ // if g_i!=g_\ell bg_split(n_2ip1[j]->reality, n_2ip1[j], n_2ip1[j]->desire->reality->desire, n_2ip1[j]->desire->reality, n, perm, x, y); n_2ip1[j] = x; } else if(interleave(n_2ip1[j], n_1[j])){ // g_1 and g_\ell does interleave bg_split(n_1[j], n_1[j]->reality, n_1[j]->desire->reality, n_1[j]->desire->reality->desire, n, perm, x, y); n_1[j] = y; // set y as new leftmost cycle } else{ // g_1 and g_\ell doesn't interleave (c) bg_split(n_2ip1[j]->reality, n_2ip1[j], n_1[j]->desire, n_1[j], n, perm, x, y); n_2ip1[j] = NULL; } } // calculate absolute positions for(elem *n1=&perm[0], *n2=perm[0].reality; n2 != NULL; n1 = n2, n2=(n2->pos%2) ? n2->co_elem : n2->reality) n2->pos = n1->pos+1; // Phase 2a: Detect interleaving edges of long cycles stack st; // stack leftmost element of an untwisted unoriented cycle for(n_s=&perm[0]; n_s!= NULL; n_s = n_s->reality->co_elem ){ // n1 left end of a reality edge while(!st.empty() && (interleave(n_s, x=st.top()) || interleave(n_s->reality, st.top()) ) ){ //find interleaving while(x->pos < n_s->pos) x = x->reality->desire; x->cycle = INTERLEAVE; st.pop(); } if(is_long_cycle(n_s) && n_s->desire->pos > n_s->pos && n_s->desire->pos > n_s->reality->desire->pos)//left end of untwisted long cycle? st.push(n_s); } // Phase 2b: Handle unoriented long cycles for(n_s=&perm[0]; n_s != NULL; ) if(is_long_cycle(n_s)){ elem *n1 = n_s, *n2 = n1->reality, *n2l = n1->desire, *n2l_1 = n2l->reality; if( n2l_1->cycle!=INTERLEAVE ) bg_split(n1, n2 ,n2l_1, n2l_1->desire, n, perm, x, y ); else bg_split(n2l_1, n2l ,n2->desire, n2, n, perm, x, y ); } else n_s = n_s->reality->co_elem; // move forward } }