「TJOJ1110」菜哭武读论文
April 22, 2018
题目描述
新格尔公司的天才程序员刚刚接了一个特别厉害的项目,所以他最近正在阅读论文找灵感。菜哭武有一个习惯就是每天给自己定一个小目标,不完成这个小目标不睡觉。
读论文期间,他把自己找到的相关的论文都编了号从1 号到1,000号,每天读一部分。
比如说今天的任务就是从编号a读到b的论文。但是今天菜哭武的心情不大好,所以他不想每一篇都读,所以他准备准备阅读编号为 a和 b的以及其中的一部分论文,并且阅读顺序有些要求,如果他读完了编号为 i的论文,那么他下一篇可以选择阅读编号为 i-2,,i+2,或者 i*2三者中的任意一篇(当然了,编号不在[1,1,000] 范围内的论文他是不会看的,但是他有可能会去看编号在[a, b]之外的论文),菜哭武读论文的速度非常快,可以忽略,但是读两篇论文之间他需要休息,休息的时间取决于他下一篇选取了哪篇论文,如果选择编号为 i*2的,那么需要休息 x分钟;如果选择编号为 i+2的 需要休息 y分钟 ;如果选择了 i-2的需要休息 z分钟。那么他想知道今天按照他的方式从 a编号的论文开始读,直到读完 b编号的论文,最少需要多少分钟。
天才程序员菜哭武自然是会算的,但是他最近心情不好呀,不想算,所以需要你帮帮忙。
输入
题目包含多组数据。
输入的第一行有一个整数 T (1≤T≤10) 代表有 T组数据。
对于每组数据分为两行:
第一行有两个整数 a,b (1≤a,b≤1,000)。
第二行有三个整数 x,y,z (1≤x,y,z≤1,000)。
输出
对于每组数据,输出的第一行为 Case #x: ,其中 x是数据编号(从1开始),
第二行,有一个整数,最少花的时间,如果永远不可能达到小目标,输出-1。
样例输入
4 1 19 1 1 1 4 7 1 2 3 4 8 100 1 1 4 10 2 100 3
样例输出
Case #1: 9 Case #2: -1 Case #3: 2 Case #4: 10
题解
把1-1000当成点,休息时间当成边权,跑最短路就行了。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstdio> #include <cmath> #include <cstring> using namespace std; int s, t, u, x, y, z; int w[1001][1001], dis[1001]; bool pd[1001][1001], used[1001]; int main() { freopen("a.txt", "r", stdin); cin >> u; for (int pp = 1; pp <= u; pp++) { memset(w, 0, sizeof(w)); memset(used, 0, sizeof(used)); memset(pd, 0, sizeof(pd)); memset(dis, 127, sizeof(dis)); scanf("%d %d", &s, &t); cin >> x >> y >> z; for (int i = 1; i <= 998; i++) { w[i][i + 2] = y; pd[i][i + 2] = 1; } for (int i = 3; i <= 1000; i++) { w[i][i - 2] = z; pd[i][i - 2] = 1; } for (int i = 1; i <= 500; i++) { w[i][i * 2] = x; pd[i][i * 2] = 1; } dis[s] = 0; for (int i = 1; i <= 1000; i++) { int mini = 0; for (int j = 1; j <= 1000; j++) if (!used[j] && dis[j] < dis[mini]) mini = j; if (mini == 0) break; used[mini] = 1; for (int j = 1; j <= 1000; j++) if (pd[mini][j] && dis[mini] + w[mini][j] < dis[j]) dis[j] = dis[mini] + w[mini][j]; } cout << "Case #" << pp << ":" << endl; if (dis[t] <= (1 << 30)) printf("%d", dis[t]); else printf("-1"); if (pp != u) printf("\n"); } return 0; }