题目
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=110383#problem/D
题目来源:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=110383#overview
简要题意:计算器可以末尾加数字,乘数字,加数字,求某数字到另一个数字的最小代价。
题解
每个点向外最多 30 个点,建图然后最短路是最简单想法。
开始用Dijkstra写了个,然后TLE了。
然后跑去看其他人的代码,由于加和乘的性质,除了乘 0 都是结果不递减的。
于是可以先加入
0 还有起点的代价,从 0 <script type="math/tex" id="MathJax-Element-4">0</script>开始向上递推。然后从其他人代码里发现了PII可以直接用来保存结果,利用内置的比较算子来更新。
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
// head
const int N = 1e5+5;
const int INF = 0x3f3f3f3f;
int c[3][15];
PII dis[N];
int changeValue(int v, int type, int x) {
if (type == 0) return v * 10 + x;
if (type == 1) return v + x;
return v * x;
}
PII bfs(int from, int to) {
memset(dis, INF, sizeof dis);
dis[0] = min(dis[0], make_pair(c[2][0], 1));
dis[from] = min(dis[from], make_pair(0, 0));
for (int i = 0; i < to; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 10; k++) {
int nxtV = changeValue(i, j, k);
int nxtC = dis[i].fi + c[j][k];
int nxtT = dis[i].se + 1;
if (nxtV > to) continue;
dis[nxtV] = min(dis[nxtV], make_pair(nxtC, nxtT));
}
}
}
return dis[to];
}
int main() {
int from, to, cas = 1;
while (scanf("%d%d", &from, &to) == 2) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 10; j++) {
scanf("%d", c[i]+j);
}
}
PII ans = bfs(from, to);
printf("Case %d: %d %d\n", cas++, ans.fi, ans.se);
}
return 0;
}