Cod sursa(job #469214)

Utilizator alex_dincaDinca Alexandru-Nicolae - UPB alex_dinca Data 6 iulie 2010 22:37:48
Problema Santa Scor 60
Compilator cpp Status done
Runda Arhiva de probleme Marime 6.7 kb
#include <cstdio>
#include <cstdlib>
#include <iostream>

#include <vector>
#include <map>
#include <algorithm>
#include <queue>

#include <ctime>

using namespace std;

#define file "santa"
#define NM 41000
#define KM 16
#define FOR(i,s,e) for(int i = (int) s; i< (int) e; ++i)
#define REP(i,n) FOR(i,0,n)
#define pb push_back
#define size(x) (int) (x.size())
#define tip(x) cout << #x << " = " << x<< endl

vector<int> m[NM];
vector<int> comp[NM];
vector<int> backc[NM];

bool cp[NM];
int c[NM], ck, curcomp;
int N, S, E, Q, sol1, sol2;
#define SM (1<<KM)
int d[SM][KM], sol[NM], sk=0;
int mk[NM], mkid=2;
int way[NM], wk; // asta va tine minte punctele de frontiera pana de la S la E generat cu get_way
int ids[KM], k, tids[NM];
int lev[NM], up[NM];


void read_data();
void getFrontier(int x=0, int f=-1);
void df(int Q);
void hamWay(); //start is always ids[0]
void buffer_way(int s, int n);
void get_way();
void split(int x=0, int f=-1, int cc=0);
bool prepare(int x, int y); // this shuld prepare ids and k s.t. x in ids[0], y is ids[1] and the rest is the component where both x and y belong to

int main() {
    freopen(file".in","rt",stdin);
    freopen(file".out","wt",stdout);

    read_data();

    getFrontier(); if (c[0]!=1) cp[0]=true;
    memset(mk, 0, sizeof(mk));

    if (!cp[0]) comp[0].pb(0);
    
    split();
//    REP(i,N) if (cp[i]) printf("%d ", i+1); printf("\n");
    FILE *DEBUG;
    DEBUG = fopen("santa.debug", "wt");
    REP(i, ck) {
	fprintf(DEBUG,"%d\n", size(comp[i]));
/*        REP(j, size(comp[i]) ) {
            printf("%d ", comp[i][j]+1);
        }
        printf("\n");*/
    }
    fclose(DEBUG);
    //Build the node->component matrix
    REP(i, ck) 
        REP(j, size(comp[i]) )
            backc[comp[i][j]].pb(i);
        
    memset(mk, 0, sizeof(mk));
//Good so far
    df(Q); // marcheaza punctele din zona curenta cu ++mkid (autoincrementat)
    curcomp=backc[Q][0];
    if ( !mk[S] && !mk[E] ) //I'm not at either start or end
    {
        printf("No chance\n");
        
        fclose(stdout);
        return 0;
    }

    if ( mk[S] && mk[E] ) // S & E are in the same component with me so just get a ham way and print it
    {
        hamWay();
        REP(i,k)
            if ( d[(1<<k)-1][i] != -1)
               buffer_way((1<<k)-1,i);
    } else {
	if ( mk[E] ) { // inseamna ca sunt in E si vreau sa ajung in S, deci swap ca sa ajung in starea normala...
	    int t=E; E=S; S=t;
	}
	get_way();
	way[0]=Q;
	REP(i, wk-1)
	{
//	    cout << way[i]+1 << " ";
    	    memset(tids,0xff,sizeof(tids));
	    if (! prepare(way[i], way[i+1]) ){
	            printf("NO\npreparefailed");
	            fclose(stdout);
    		    return 0;
	    }	    
	    hamWay();
	    if ( d[(1<<k)-1][1] == -1) {
	            printf("NO\nimposible way");
		    
		    for(int i=0; i<k; i++)
		    {
			printf("%d : ", ids[i]);
			for(int j=0; j<size(m [ids[i]]); ++j)
			    if (tids[ m[ids[i]][j] ]!=-1)
				printf("%d ", m[ids[i]][j]);
			printf("\n");
		    }
	            fclose(stdout);
    		    return 0;
	    }
	    buffer_way((1<<k)-1, 1);
	    sk--; // Not to repeate frontier nodes it will be added again by the next component
	}
	sol[sk++]=E;
	//cout << endl;
    }
	
    
    printf("%d\n", sk);
    
    REP(i, sk)
	printf("%d ", sol[i]+1);

    fclose(stdout);
    return 0;
}

int getCommonComponent(int x, int y)
{
    REP(i, size(backc[x]))
	REP(j, size(backc[y]))
	    if (backc[x][i] == backc[y][j]) return backc[x][i];
    return -1;
}

bool prepare(int x, int y) // this shuld prepare ids and k s.t. x in ids[0], y is ids[1] and the rest is the component where both x and y belong to
{
    int w=getCommonComponent(x,y);
    if (w==-1) return false;
    curcomp=w;
    k=0;
	++k;
    ids[k-1]=x;
	++k;
	ids[k-1]=y;
    tids[x]=0; tids[y]=1;
    REP(i, size(comp[w]) )
	if ( (comp[w][i] != x) && (comp[w][i] != y) )
	    tids[comp[w][i]]=k, ids[k++]=comp[w][i];
    return true;
}

void split(int x, int f, int cc) {
    mk[x]=1;
    REP ( i,size(m[x])) 
    if ( m[x][i]!=f ) {
        if ( ! mk[ m[x][i] ] ) {
	    if (cp[x] && (up[ m[x][i] ]>=lev[x])) {
		comp[ck].pb(x);
		comp[ck].pb(m[x][i]);
		ck++;
		split(m[x][i], x, ck-1);
	    } else {
		comp[cc].pb(m[x][i]);
		split( m[x][i], x, cc);
	    }
	}
    }
}

void get_way() {
    bool mk[NM]; memset(mk,0, sizeof(mk));
    int f[NM]; 
    int q[NM], s,e;
    s=0;
    e=1;
    f[S]=-1;
    q[0]=S;mk[S] = true;
    while (s<e){
	REP(i, size(m[q[s]]) ) 
	    if (!mk[ m[q[s]][i] ]){
		q[e++]=m[q[s]][i];
		mk[q[e-1]] = true;
		f[ q[e-1]] = q[s];
	    }
	s++;
    }
    //REP(i,e) cout << q[i]+1<<","<< f[q[i]]+1 << "    "; cout << endl;
    e=2;s=f[E];
    while (s!=S) {
	if ( cp[s] ) ++e;
	s=f[s];
    }
    s=f[E];wk=e;
    way[--e]=E;
    while (s!=S) {
	if ( cp[s] ) way[--e]=s;    
	s=f[s];
    }
    way[--e]=S;
}




void buffer_way(int s, int n) {
    if ( d[s][n] )
	buffer_way( d[s][n]/KM, d[s][n]%KM );
    sol[sk++]= ids[n];
}


void hamWay() {
     memset(d, 0xff, sizeof(d));
     d[1][0] = 0; queue<int> w;
     w.push(1*KM + 0);
     while (! w.empty() )
     {
        int state = w.front() /KM;
        int nod = w.front() % KM;

        REP(i, size(m[ids[nod]]))
        {
            if ( (tids[ m[ ids[nod] ][i] ]!=-1) && ( ! (state & (1<<tids[ m[ ids[nod] ][i] ])==0)) && 
	          d[state | (1<<tids[ m[ ids[nod] ][i] ])][ tids[ m[ ids[nod] ][i] ] ]==-1  ) {
               d[state | (1<<tids[ m[ ids[nod] ][i] ])][ tids[ m[ ids[nod] ][i] ] ]= w.front();
               w.push( (state | (1<<tids[ m[ ids[nod] ][i] ]))*KM + tids[ m[ ids[nod] ][i] ] );
            }
        }
        w.pop();
     }
}


void df(int Q) {
     mkid++;
     k = 1; ids[0] = Q; tids[Q] = 0;
     queue<int> w;
     w.push(Q);
     mk[Q] = mkid;
     while ( ! w.empty() )
     {
        int c = w.front(); w.pop();
        if ( ! cp[c] )
        REP ( i, size(m[c]))
            if ( mk[ m[c][i] ] == 0 )
            {
                mk[ m[c][i] ] = mkid;
                w.push(m[c][i]);
                tids[m[c][i]]=k;
                ids[k++] = m[c][i];
            }
     }
}

void getFrontier(int x, int f) {

    up[x] = lev[x];
    mk[x] = true;
    c[x] = 0;
    cp[x] = false;
    
    REP ( i,size(m[x])) 
    if (m[x][i]!=f) {
        if ( ! mk[ m[x][i] ] ) {
           c[x]++;
           lev[ m[x][i] ] = lev[x] +1;
           getFrontier( m[x][i], x);
           if ( ! ( up[ m[x][i] ] < lev[x] )) cp[x] = true;
           if ( up[ m[x][i] ] < up[x] ) up[x] = up[m[x][i]];
        } else if ( (m[x][i] != f) && (lev[ m[x][i] ] < up[x]) )
          up[x] = lev[ m[x][i] ];
    }
}


void read_data() {
     int M,x,y;
     scanf("%d%d", &N, &M);
     REP(i,M) {
              scanf("%d%d", &x, &y);x--,y--;
              m[x].pb(y);
              m[y].pb(x);
     }
     scanf("%d%d%d", &S, &E, &Q);
     S--,E--,Q--;
}