题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=842&problem=4014&mosmsg=Submission+received+with+ID+15350118
#include <cstdio>
#include <set>
#include <vector>
#include <queue>
#include <cstdlib>
#include <cstring>
using namespace std;
// next[i]代表与i相连的点
vector<int> next[20];
// 代表起点和终点
int s, t;
// 代表点的数目
int n;
// 代表障碍物数目
int m;
// 记录状态的结构体
typedef struct s_node
{
// int place[20]; // place[0]为机器人位置,place[1...]为障碍物位置
// int not_free[20]; // not_free[i] = 1代表i节点有东西占据
int not_free_int; // 哪些位为1代表哪些位被占用
int r_place; // 代表robot位置
// int path[1000]; // 路径
int from, to;
int path_length;
struct s_node* parent;
}s_node;
// 记录所有的状态(robot和障碍物的位置)
set<pair<int,int> > state_set;
// 广度优先搜索所用的队列
queue<s_node*> my_queue;
int visit[40000][16];
s_node* root;
int main()
{
int num;
scanf("%d", &num);
int count = 0;
while(count < num)
{
for(int i = 0; i < 20; i++)
next[i] = vector<int>();
// state_set = set<vector<int> >();
my_queue = queue<s_node*>();
memset(visit, 0, sizeof(visit));
scanf("%d %d %d %d", &n, &m, &s, &t);
// 记录robot和障碍物的初始位置
/* vector<int> array;
array.push_back(s);
*/
// 读取障碍物的位置
int not_free[20];
memset(not_free, 0, sizeof(not_free));
not_free[s] = 1;
for(int i = 1; i <= m; i++)
{
int x;
scanf("%d", &x);
// array.push_back(x);
not_free[x] = 1;
}
// 记录边
for(int i = 1; i <= n-1; i++)
{
int x, y;
scanf("%d%d", &x, &y);
next[x].push_back(y);
next[y].push_back(x);
}
// 将初始节点加入队列
s_node* p = (s_node*)malloc(sizeof(s_node));
p->not_free_int = 0;
p->r_place = s;
/* memset(p->not_free, 0, sizeof(p->not_free));
for(int i = 0; i < array.size(); i++)
{
p->place[i] = array[i];
p->not_free[p->place[i]] = 1;
}
int not_free_int = 0;
*/ for(int i = 1; i <= n; i++)
p->not_free_int = p->not_free_int*2 + not_free[i];
p->path_length = 0;
p->parent = NULL;
my_queue.push(p);
visit[p->not_free_int][p->r_place] = 1;
// state_set.insert(array);
// state_set.insert
root = p;
// 广度优先搜索
while(my_queue.size() > 0)
{
s_node* p = my_queue.front();
my_queue.pop();
/*
printf("path: ")
for(int i = 0; i < path_length-1; i = i+2)
printf("(%d,%d) ", p->path[i], p->path[i+1]);
printf("\n");
printf("not free: ")
for(int i = 0; i < n; i++)
{
if(p->not_free[i] == 1)
printf("%d ", i)
}
*/
// 检查机器人是否到终点
if(p->r_place == t)
{
printf("Case %d: %d\n", count+1, p->path_length);
/*
for(int i = 0; i <= p->path_length-2; i = i+2)
printf("%d %d\n", p->path[i], p->path[i+1]);*/
if(p != root)
{
int path[1000];
int p_count = 0;
s_node* begin = p;
while(begin != root)
{
path[p_count] = begin->from;
path[p_count+1] = begin->to;
p_count = p_count+2;
begin = begin->parent;
}
for(int i = p_count-2; i >= 0; i= i-2)
{
printf("%d %d\n", path[i], path[i+1]);
}
}
// printf("\n");
break;
}
// 如果可能,尝试机器人和障碍物的位置变换
/* vector<int> this_array;
for(int i = 0; i < m+1; i++)
this_array.push_back(p->place[i]);
*/
int not_free[20];
memset(not_free, 0, sizeof(not_free));
for(int i = 1; i <= n; i++)
not_free[i] = (p->not_free_int & (1 << (n-i))) >> (n-i);
/*
int this_int = 0;
for(int i = 1; i <= n; i++)
this_int = this_int*2 + p->not_free[i];
int r_place = p->place[0];
*/
for(int i = 1; i <= n; i++)
{
if(not_free[i] == 0)
continue;
// int now_s = p->place[i];
int now_s = i;
for(int j = 0; j < next[now_s].size(); j++)
{
int now_t = next[now_s][j];
// if(p->not_free[now_t] == 0)
if(not_free[now_t] == 0)
{
int next_int = p->not_free_int - (1 << (n-now_s)) + (1 << (n-now_t));
int next_r_place;
if(i == p->r_place)
next_r_place = now_t;
else
next_r_place = p->r_place;
/* int tmp = this_array[i];
this_array[i] = now_t;
if(state_set.find(this_array) == state_set.end())
*/
if(visit[next_int][next_r_place] == 0)
{
// state_set.insert(this_array);
visit[next_int][next_r_place] = 1;
s_node* q = (s_node*)malloc(sizeof(s_node));
/* for(int k = 0; k < m+1; k++)
// q->place[k] = this_array[k];
q->place[k] = p->place[k];
q->place[i] = now_t;
for(int k = 1; k <= n; k++)
q->not_free[k] = p->not_free[k];
q->not_free[now_s] = 0;
q->not_free[now_t] = 1;
*/
q->not_free_int = next_int;
q->r_place = next_r_place;
/* for(int k = 0; k < p->path_length; k++)
q->path[k] = p->path[k];
q->path[p->path_length] = now_s;
q->path[p->path_length+1] = now_t;
*/
q->from = now_s;
q->to = now_t;
q->path_length = p->path_length+1;
q->parent = p;
my_queue.push(q);
}
// this_array[i] = tmp;
}
}
}
}
if(my_queue.size() == 0)
printf("Case %d: -1\n", count+1);
printf("\n");
count++;
}
return 0;
}
这道题觉得可以用BFS,没有剪枝,TLE.
以为是剪枝的问题,看了别人的思路,要把状态压缩:数组压缩为整数。(哪些结点被占,机器人的位置)。两个数组压缩为两个整数,然后查表来确定该状态是否被遍历过,而不是用集合set来存储状态。仍然TLE, 将最后能优化的部分:每个节点不存全部的变换路径,而是只存自己变换的那一步,等到最后遍历到终点,再从该节点一直往上搜到根节点来打印路径。然后通过。