题目
环形跑道给定n个加油站(n<=100000),编号从1到n,输入Pi表示第i个加油站可以加油Pi加仑,Qi表示第i到第i + 1个加油站消耗油量。初始油箱为空,求选择一个起点,使得可以走完一圈回到起点。如果无解输出Not possible,否则输出可以选择的最小起点。
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define ll long long
const int maxn = 100000 + 1000;
int gas[maxn], dis[maxn], n;
// dis[i]表示 i 与 (i+1)%n 的距离
int solve() {
int start = 0, s = 0; ll g = 0;
while (start < n) {
//printf("start: %d s: %d\n", start, s);
g += gas[s];
if ((s + 1) % n == start) {
if (g >= dis[s])
return start;
else
return -1;
}
if (g < dis[s]) {
if (s < start) return -1; // 1,2,...,start-1都非解,而此时s<start,证明s遍历回来了,即start,start+1,...,n-1都不是解。直接驳回。
start = s + 1;
g = 0;
s = start;
}
else {
g -= dis[s];
s = (s + 1) % n;
}
}
return -1;
}
int main() {
int T, kase = 0;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%d", &gas[i]);
for (int i = 0; i < n; i++) scanf("%d", &dis[i]);
int ans = solve();
if (ans == -1) printf("Case %d: Not possible\n", ++kase);
else printf("Case %d: Possible from station %d\n", ++kase, ans+1);
}
return 0;
}
思路
1.暴力:枚举每个点(O(n)),并判断(O(n))。 复杂度:
O(n2)
O
(
n
2
)
2.暴力+剪枝:枚举每个点,并判断。若从点i出发,在点j到点j+1的路上没油的,那么i,i+1,…,j-1,j都绝对不是解,直接排除。 复杂度:
O(n)
O
(
n
)
- 原因:对于点i到点j后,j点油量p1;点i+1到点j后,j点油量p2。则必有p1>=p2。p1尚且不能从j走到j+1,p2更不可能了。