HDU 1026 Ignatius and the Princess I(BFS、优先队列)

看到这一题首先想到的是深搜或者dp,后来深入了解了一下题意,把dp否定了,然后尝试着用深搜去解。但是在模拟的过程中发现深搜的耗费会很大,于是就去网上搜了一下,网上大神是用广搜和优先队列,看了一下代码,有一种茅塞顿开的感觉。

首先,采用map数组模拟墙、路和怪,flag数组存储走的方向,blood数组存储怪的血量;

然后用重载排序的优先队列对当前节点的所有可能节点进行广搜;

到达目的点后,对到达该点的节点进行flag数组的反操作(flag数组存储的是当前点到下一点需要走的x、y值),即进行回溯操作,打表记录路径,再递归打印即可;

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
int m,n,temp;
int map[111][111];//地图
int blood[111][111];//怪的血量
int flag[111][111];//记录走的路径
int dir[4][2]={0,1,1,0,0,-1,-1,0};//能走的4个方向
struct node{
    int x;
    int y;
    int step;
    friend bool operator<(node a,node b){
        return b.step<a.step;//step小的节点优先出列
    }
}now,nnext;

int bfs(){
    priority_queue<node>q;//建立优先队列
    now.x=1;//因为我把整个地图向右下平移,所以从(1,1)出发
    now.y=1;
    now.step=0;
    map[1][1]=-1;
    q.push(now);
    while(!q.empty()){
        now=q.top();
        q.pop();
        if(now.x==m&&now.y==n) return now.step;//到达目的点返回
        for(int i=0;i<4;i++){//当前节点所有能走的点进行入队(广搜)
            nnext.x=now.x+dir[i][0];
            nnext.y=now.y+dir[i][1];
            if(map[nnext.x][nnext.y]==-1) continue;
            nnext.step=now.step+1+map[nnext.x][nnext.y];//不是墙的话将其入队
            flag[nnext.x][nnext.y]=i+1;
            map[nnext.x][nnext.y]=-1;
            q.push(nnext);
        }
    }
    return -1;
}

void output(int x,int y){
    int x_next,y_next;
    if(flag[x][y]==0) return;
    x_next=x-dir[flag[x][y]-1][0];//回溯打印路径
    y_next=y-dir[flag[x][y]-1][1];
    output(x_next,y_next);
    printf("%ds:(%d,%d)->(%d,%d)\n",temp++,x_next-1,y_next-1,x-1,y-1);//因为我把map数组向右下平移,所以所有的节点值减一
    while(blood[x][y]--)
        printf("%ds:FIGHT AT (%d,%d)\n",temp++,x-1,y-1);
}

int main(){
    char str[111];
    int ans;
    while(~scanf("%d%d",&m,&n)){
        memset(map,-1,sizeof(map));//将map的初始值赋-1,为了方便下一步直接留出边界
        memset(blood,0,sizeof(blood));
        memset(flag,0,sizeof(flag));
        for(int i=0;i<m;i++){
            scanf("%s",str);
            for(int j=0;j<n;j++){
                if(str[j]=='.')
                    map[i+1][j+1]=0;//不对i、j进行操作而对i+1、j+1进行操作,即将map向右下平移,留出一圈值为-1的墙(边界)
                else if(str[j]=='X')
                    map[i+1][j+1]=-1;
                else
                    map[i+1][j+1]=blood[i+1][j+1]=str[j]-'0';
            }
        }
        ans = bfs();
        if(ans==-1) printf("God please help our poor hero.\n");
        else{
            printf("It takes %d seconds to reach the target position, let me show you the way.\n",ans);
            temp=1;
            output(m,n);
        }
        printf("FINISH\n");
    }
    return 0;
}



对于HDU4546问题,还可以使用优先队列(Priority Queue)来解决。以下是使用优先队列的解法思路: 1. 首先,将数组a进行排序,以便后续处理。 2. 创建一个优先队列(最小堆),用于存储组合之和的候选值。 3. 初始化优先队列,将初始情况(即前0个数的组合之和)加入队列。 4. 开始从1到n遍历数组a的元素,对于每个元素a[i],将当前队列中的所有候选值取出,分别加上a[i],然后再将加和的结果作为新的候选值加入队列。 5. 重复步骤4直到遍历完所有元素。 6. 当队列的大小超过k时,将队列中的最小值弹出。 7. 最后,队列中的所有候选值之和即为前k小的组合之和。 以下是使用优先队列解决HDU4546问题的代码示例: ```cpp #include <iostream> #include <vector> #include <queue> #include <functional> using namespace std; int main() { int n, k; cin >> n >> k; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } sort(a.begin(), a.end()); // 对数组a进行排序 priority_queue<long long, vector<long long>, greater<long long>> pq; // 最小堆 pq.push(0); // 初始情况,前0个数的组合之和为0 for (int i = 0; i < n; i++) { long long num = pq.top(); // 取出当前队列中的最小值 pq.pop(); for (int j = i + 1; j <= n; j++) { pq.push(num + a[i]); // 将所有加和结果作为新的候选值加入队列 num += a[i]; } if (pq.size() > k) { pq.pop(); // 当队列大小超过k时,弹出最小值 } } long long sum = 0; while (!pq.empty()) { sum += pq.top(); // 求队列中所有候选值之和 pq.pop(); } cout << sum << endl; return 0; } ``` 使用优先队列的方法可以有效地找到前k小的组合之和,时间复杂度为O(nklog(k))。希望这个解法对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值