春季算法练习1005

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
/*杭电春季赛1 1005 航线
	小根堆优化dijkstra
*/
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
using vi = vector<int>;
using vll = vector<long long>;

const int N = 1e5 + 10, inf = (1LL << 60) - 1, mod = 1e9 + 7;
const int dx[4] = {0, -1, 0, 1};
const int dy[4] = {1, 0, -1, 0};

int n, m, t[N], d[N];
int dis[N][4];//将一个点拆成4个方向的点
bool vis[N][4];//如上
//把x,y变成一维
int encode(int x, int y) {
	return (x - 1) * m + y;
}
//再把一维变成二维
pii decode(int id) {
	return make_pair((id - 1) / m + 1, (id - 1) % m + 1);
}

void wyx() {
	cin >> n >> m;
	for (int i = 1; i <= n; i ++ ) {
		for (int j = 1; j <= m; j ++ ) {
			cin >> t[encode(i, j)];
		}
	}
	for (int i = 1; i <= n; i ++ ) {
		for (int j = 1; j <= m; j ++ ) {
			cin >> d[encode(i, j)];
		}
	}
	int st = encode(1, 1);
	int ed = encode(n, m);
	for (int i = 1; i <= n * m; i ++ ) {
		for (int j = 0; j < 4; j ++ ) {
			dis[i][j] = inf;
			vis[i][j] = 0;
		}
	}
	priority_queue<
		tuple<int, int, int>, 
		vector<tuple<int, int, int>>, 
		greater<tuple<int, int, int>>> pq;//用tuple来存储花销,位置,方向
	//pq默认大根堆,模板第一个参数是存储的元素类型,第二个参数是底层容器类型,第三个参数是比较器类型
	//若要改成小根堆就需要定义成priority_queue<xxx, vector<xxx>, greater<xxx>>
	dis[st][0] = t[st];
	pq.emplace(0, st, 0);//emplace对于插入复杂对象时可以直接构造对象,push适合已经构造好的对象
	while (!pq.empty()) {
		auto [val, p, u] = pq.top();
		pq.pop();
		if (vis[p][u]) continue;
		vis[p][u] = 1;//已访问的位置不需要访问了
		for (int v = 0; v < 4; v ++ ) {
			if (dis[p][u] + d[p] >= dis[p][v]) continue;
			dis[p][v] = dis[p][u] + d[p];
			pq.emplace(dis[p][v], p, v);
		}//更新一个点不同方向的最小花费
		auto [x, y] = decode(p);
		x += dx[u], y += dy[u];
		int q = encode(x, y);
		auto outmap = [&](int x, int y) {
			return x < 1 || x > n || y < 1 || y > m;
		};//判断越界
		if (!outmap(x, y) && dis[p][u] + t[q] < dis[q][u]) {
			dis[q][u] = dis[p][u] + t[q];
			pq.emplace(dis[q][u], q, u);
		}
	}
	cout << dis[ed][3] << endl;
	
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t = 1;
	cin >> t;
	while (t--) {
		wyx();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值