九度oj-1091

题目描述:

有一个6*6的棋盘,每个棋盘上都有一个数值,现在又一个起始位置和终止位置,请找出一个从起始位置到终止位置代价最小的路径:
1、只能沿上下左右四个方向移动
2、总代价是没走一步的代价之和
3、每步(从a,b到c,d)的代价是c,d上的值与其在a,b上的状态的乘积
4、初始状态为1

每走一步,状态按如下公式变化:(走这步的代价%4)+1。

输入:

第一行有一个正整数n,表示有n组数据。
每组数据一开始为6*6的矩阵,矩阵的值为大于等于1小于等于10的值,然后四个整数表示起始坐标和终止坐标。

输出:

输出最小代价。

样例输入:

1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
0 0 5 5

样例输出:

23

BFS代码:

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

struct Node  
{  
    int x, y, sum, statu;  
};  

int ans;  
int map[6][6];  
int opt[6][6][4]; //记录最优解,剪枝条件。4中状态都要记录  
Node start;  
int ex, ey;  
int cnt = 0;  
int dir[4][2] = {{ 0, 1 },{ 1, 0 },{ 0, -1 },{ -1, 0 } };  
queue<Node> q;  
void bfs(Node n)  
{  
    q.push(n);  
    int tempx, tempy, cost;  
    while (!q.empty())  
    {  
        cnt++;  
        Node tn = q.front();  
        q.pop();  
        for (int i = 0; i < 4; i++)  
        {  
            tempx = tn.x + dir[i][0];  
            tempy = tn.y + dir[i][1];  
            if (tempx >= 0 && tempx < 6 && tempy >= 0 && tempy < 6)  
            {  
                cost = tn.statu * map[tempx][tempy];  
                //如果这一步比以前的某一步代价还大  或者 比到终点的代价还大  
                if (tn.sum + cost < opt[tempx][tempy][cost % 4 ] && tn.sum + cost < opt[ex][ey][cost % 4 ])  
                {  
                    opt[tempx][tempy][cost % 4] = tn.sum + cost;  
                    Node temp;  
                    temp.x = tempx;  
                    temp.y = tempy;  
                    temp.sum = tn.sum + cost;  
                    temp.statu = cost % 4 + 1;  
                    q.push(temp);  
                }  
            }  
        }  
    }  

}  

int main()  
{  
    int k;  
    cin >> k;  
    while (k--)  
    {  
        for (int i = 0; i < 6; i++)  
            for (int j = 0; j < 6; j++)  
            {  
                cin >> map[i][j];  
                for(int k=0; k<4; k++)  
                    opt[i][j][k] = 100000;  
            }  
        start.sum = 0;  
        start.statu = 1;  
        ans = 100000;  
        cin >> start.x >> start.y >> ex >> ey;  
        bfs(start);  
        for (int i = 0; i < 4; i++)  
        {  
            if (ans > opt[ex][ey][i])  
                ans = opt[ex][ey][i];  
        }  
        //cout << cnt << endl;  
        cout << ans << endl;  
    }  
    return 0;  
}  

DFS代码:

#include <iostream>  
using namespace std;  
int map[6][6];  
int sx,sy,ex,ey,ans;  
int cnt = 0;  
int dir[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };  
bool visit[6][6];  
void dfs(int x,int y,int sum,int statu){  
    cnt ++;  
    if(sum < ans){  
        if(x == ex && y == ey){  
                 ans = sum;  
                return;  
        }  
        for(int i=0; i<4; i++){  
            int tempx = x + dir[i][0];  
            int tempy = y + dir[i][1];  
            if(visit[tempx][tempy] && tempx >=0 && tempx < 6 && tempy >=0 && tempy < 6){  
                int cost = statu * map[tempx][tempy];  
                visit[tempx][tempy] = false;  
                dfs(tempx, tempy, sum+cost, cost % 4 + 1);  
                visit[tempx][tempy] = true;  
            }  
        }  
    }  
}  

int main() {  
    int k;  
    cin >> k;  
    while(k--){  
        for(int i=0; i<6; i++)  
            for(int j=0; j<6; j++){  
                 cin >> map[i][j];  
                 visit[i][j] = true;  
            }  
        cin >> sx >> sy >> ex >> ey;  
        ans = 1000000;  
        dfs(sx,sy,0,1);  
        //cout  << cnt << endl;  
        cout << ans << endl;  
    }  
    return 0;  
}  

作者提醒:

DFS利用递归,不必使用多余的数据结构,实现简单。但要注意剪枝。

BFS借助队列,往往在求最优解时使用。总是能找到最优解,某些情况下也要剪枝。

这两种方法根据具体问题来使用。

以此题为例,DFS和BFS都可求解。

由于是求最优解,用BFS更为直接。

由于此题的不确定性,必须要考虑所有可能情况,结合剪枝。