http://acm.pku.edu.cn/JudgeOnline/problem?id=1137
Код:
#include <stdio.h>
#include <stdlib.h>
#define MAX_ROOMS 10
#define QUEUE_LEN 11000
#define CODENUM (1<<MAX_ROOMS)*MAX_ROOMS
typedef struct
{
int exnum,lightnum;
int exit[MAX_ROOMS];
int light[MAX_ROOMS];
} room;
FILE *inp;
int n,goal;
int queue[QUEUE_LEN],qhead,qtail;
short sit[CODENUM],back[CODENUM];
room r[MAX_ROOMS];
int caseno = 1;
/* Queue management */
void qinit() { qhead = qtail = 0; }
int qempty() { return qhead == qtail; }
void qpush(int pos, short dist, short bck)
{
if(sit[pos] != -1)
{
/* printf("*** INPUT ERROR: multiple solutions!\n"); */
return;
}
sit[pos] = dist;
back[pos] = bck;
queue[qtail] = pos;
qtail = (qtail+1)%QUEUE_LEN;
if(qtail == qhead)
{
printf("*** ERROR: Queue size too small!\n");
}
}
int qpop()
{
int tmp;
if(qhead == qtail) return -1;
tmp = queue[qhead];
qhead = (qhead+1)%QUEUE_LEN;
return tmp;
}
/* Converter for integer<->situation */
int situation2int(int pos, int *light)
{
int b,cod,i;
for(code=i=0,b=1;i<n;i++,b<<=1)
if(light[i]) cod += b;
return cod*n+pos;
}
void int2situation(int cod, int *pos, int *light)
{
int i;
*pos = cod%n;
cod /= n;
for(i=0;i<n;i++,cod>>=1)
light[i] = cod & 1;
}
void print_sol(int cod)
{
if(back[cod] == -1) return;
if(back[cod] < n) /* movement */
{
print_sol(n*(cod/n)+back[cod]);
printf("- Move to room %d.\n",cod%n+1);
}
else /* switch light */
{
print_sol(((cod/n)^(1<<(back[cod]-n)))*n+cod%n);
printf("- Switch %s light in room %d.\n",
(cod/n)&(1<<(back[cod]-n))?"on":"off",back[cod]-n+1);
}
}
/* We solve the problem by brute force. By breadth-first search we
enumerate all possible cases */
void solve_case()
{
int i;
int light[MAX_ROOMS],pos,cod,dist;
for(i=0;i<(1<<n)*n;i++) sit[i] = -1;
pos = 0; light[0] = 1;
for(i=1;i<n;i++) light[i] = 0;
cod = situation2int(pos,light);
dist = 0;
qinit();
qpush(cod,dist,-1);
while(!qempty())
{
cod = qpop(); dist = sit[cod];
int2situation(cod,&pos,light);
/* compute successors */
/* a) move into another room */
for(i=0;i<r[pos].exnum;i++)
if(light[r[pos].exit[i]]) /* enter only rooms that have light */
{
cod = situation2int(r[pos].exit[i],light);
qpush(cod,dist+1,pos);
}
/* b) turn on/off lights */
for(i=0;i<r[pos].lightnum;i++)
if(r[pos].light[i] != pos) /* do not turn off light in current room */
{
light[r[pos].light[i]] = 1-light[r[pos].light[i]];
cod = situation2int(pos,light);
qpush(cod,dist+1,n+r[pos].light[i]);
light[r[pos].light[i]] = 1-light[r[pos].light[i]];
}
}
/* output the solution */
printf("Villa #%d\n",caseno++);
for(i=0;i<n-1;i++) light[i] = 0;
light[n-1] = 1;
cod = situation2int(n-1,light);
if(sit[cod] == -1)
printf("The problem cannot be solved.\n\n");
else
{
printf("The problem can be solved in %d steps:\n",sit[cod]);
print_sol(cod);
printf("\n");
}
}
/* read in the data */
void skip_line() { while(getc(inp) >= ' '); }
int comp_int(const void *a, const void *b)
{
return *((const int *)a)-*((const int *)b);
}
int read_case()
{
int i,d,s,a,b;
fscanf(inp,"%d %d %d",&n,&d,&s); skip_line();
if(n == 0) return 0;
for(i=0;i<n;i++)
r[i].exnum = r[i].lightnum = 0;
for(i=0;i<d;i++)
{
fscanf(inp,"%d %d",&a,&b); skip_line();
r[a-1].exit[r[a-1].exnum++] = b-1;
r[b-1].exit[r[b-1].exnum++] = a-1;
}
for(i=0;i<s;i++)
{
fscanf(inp,"%d %d",&a,&b); skip_line();
r[a-1].light[r[a-1].lightnum++] = b-1;
}
/* This is completely unnecessary, but gives nicer (= ordered) output
later */
for(i=0;i<n;i++)
{
qsort(r[i].exit,r[i].exnum,sizeof(int),comp_int);
qsort(r[i].light,r[i].lightnum,sizeof(int),comp_int);
}
return 1;
}
int main()
{
inp = stdin; // fopen("villa.in","r");
while(read_case()) solve_case();
// fclose(inp);
return 0;
}