您的位置:首页 > 其它

【算法学习笔记】87. 枚举路径 SJTU OJ 1999 二哥找宝藏

2015-07-29 00:07 519 查看
这个题只用BFS来搜索一次会很麻烦, 因为每次经过一个宝藏之后,要把所有的vis重置(因为可以重复经过同一点, 但是这样会有很多不必要的路径)

看题目的暗示 最多只有5个宝藏 我们要把所有的宝藏收集齐全, 如果确定了收集的顺序, 那么也就确定了路径

那么可以知道 A55的排列一共是120种路径 遍历起来毫无压力

我们枚举所有宝藏的全排列, 然后从起点开始走, 记录整个路径的步数, 最后取最小值即可.

这里生产全排列的方法利用了 STL的next_permutation函数 非常爽....(要引入algorithm)

计算路径长度需要计算的只有

1.起点到各个宝藏的最短距离

2.每两个宝藏之间的最短距离

所以我们用了一个dp来记忆化存储这些路径 避免重复计算

每个最短距离 用bfs来算就好了

//有一个小优化 就是 C62时一旦有任意两个box之间的距离无法达到 则直接返回-1 这样比较快

#include <iostream>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;

int n,m;
int map[100+5][100+5];
bool vis[100+5][100+5];
int dx[] = {-1,1,0,0};
int dy[] = {0,0,-1,1};
int dp[6][6]={0};//dp[i][j] 表示 ibox和jbox 的距离 dp[5][i] 表示起点 到i box的距离
struct Point
{
int x;
int y;
int id;
int step;
Point(int i=0,int j =0):x(i),y(j){
step = 0;
id = 0;
}
};
Point start;//二哥的起点
Point boxes[5];//最多五个宝藏
int path[5];//枚举的线路
int len = 0; //宝藏的个数

void init(){
cin>>n>>m;
for (int i = 1; i <= n; ++i){
for (int j = 1; j <= m; ++j){
cin>>map[i][j];
if(map[i][j]==1){
boxes[len].x = i;
boxes[len].y = j;
path[len] = len;
len++;
}
if(map[i][j]==2){
start.x = i;
start.y = j;
start.id = 2;
start.step = 0;
}
}
}
}

//
int bfs(Point s, Point e){

queue<Point> q;
memset(vis,false,sizeof(vis));
s.step = 0;
q.push(s);
while(!q.empty()){
Point cur = q.front();
q.pop();
vis[cur.x][cur.y] = true;
Point next;
for (int i = 0; i < 4; ++i)
{
next.x = cur.x + dx[i];
next.y = cur.y + dy[i];
if(next.x>=1 and next.x<=n and next.y>=1 and next.y<=m)
{
if(vis[next.x][next.y])
continue;
next.id = map[next.x][next.y];
vis[next.x][next.y] = true;
if(next.id != -1){
next.step = cur.step + 1;
if(next.x == e.x and next.y == e.y)//到达了终点
return next.step;
q.push(next);
}
}
}

}
return -1; //找不到
}

int build(){
//枚举取宝藏的顺序  从而形成路径 求出最小的一个即可 方案数最多 A55 = 120种
//求一下C62的dp
//生成dp
for (int i = 0; i < len; ++i)
{
dp[5][i] = bfs(start,boxes[i]);
if(dp[5][i]==-1)
return -1;
}

for (int i = 0; i < len; ++i)
{
for (int j = i+1; j < len; ++j)
{
dp[i][j] = dp[j][i] = bfs(boxes[i],boxes[j]);
if(dp[i][j]==-1)
return -1;
}
}
int ans = 1<<30;
do{
int dis = dp[5][path[0]];
for (int i = 1; i < len; ++i)
{
dis += dp[path[i]][path[i-1]];
}
ans = min(ans,dis);
}while(next_permutation(path,path+len));
return ans;
}
int main(int argc, char const *argv[])
{
init();
cout<<build()<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: