给定n个加油站,形成一个环,每个加油站有一些油,从一个加油站行驶到另一个加油站需要消耗一些油,问最小可以从哪个点出发使得能够回到出发点;
这是一道模拟,首先模拟第一个点,如果从P点不能到P+1点(假设2<P<n),那么第一个点到第P个点一定都不是问题的解;因为如果从第一个点出发,能够到达第二个点,那么在第二个点未加油时油量是大于等于0的,而从第一个点出发到不了P点,以此类推,从第二个点,从第三个点,出发到达P点的油量一定小于等于从第一个点到达P点的油量,而从第一个点不能到达P+1,所以从2~P都不能到达P+1;所以如果模拟1不行,就再模拟P+1;先用sum保存一个加油站的油量,然后计算sum - A[i][1]是否大于0,如果是,就继续模拟,但需要特判一下i;如果i == n; i = 1;else i++; 就是要形成环;如果否,就用一个数组记录下一个要模拟的的点,即i+1;if(k[cur]- k[cur-1]<= 0)证明已经模拟过一圈了,并且都不符合,这时就break;还有一种判断就是当i == n的时候断了,这时说明下一次要模拟第一个点,证明一定是模拟了超过一圈了,这时直接break就行,不直接break也可以;如果还能继续模拟,要令sum = 0,重新开始,模拟P+1;出了判断后要记得给sum加上到达油站的油;循环条件是1就可以;反正最后会break;
1、还有一个问题,由于开始令k[cur] = i;而当进入循环时会判断k[cur]是否等于i;如果是,就有解,那么怎么规避呢,设一个st = 0;然后在判断是加上&& st;这样在判断完后如果i == k[cur] && !st; st = 1;这样就能规避第一次就相等的错误;然后如果模拟到sum小于0不符合了,也要再令st = 0;重新开始;
2、还有一个问题,就是如何判断已经跑了一圈了但是还没找到解的问题,因为开了一个数组来记录模拟的位置,如果没有模拟完一圈那么这时k[cur] - k[cur-1]一定是大于0的,因为是从1开始模拟,模拟到n;而如果小于等于0,就证明了已经跑完了一圈,还没找到答案,这时就要break;
3、还有一个问题,如何判断break之后是否找到了答案呢?设一个ok = 0;如果找到答案,ok = 1;否则ok一直为0;如果ok,就证明找到,否则,就没找到;
4、小问题,不用初始化k[0]为0,虽然从1开始记录,但不会出现k[1] - k[0] <= 0的情况;因为k[0]一直为0;
ok了
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
const int maxn = 1e5+10;
ll A[maxn][2], k[maxn];
int main()
{
int T;
scanf("%d",&T);
int ans;
ll sum;
int cnt = 1;
while(T--)
{
sum = 0;
int n;
scanf("%d",&n);
for(int i = 1; i <= n; i++)
scanf("%lld",&A[i][0]);
for(int i = 1; i <= n; i++)
scanf("%lld",&A[i][1]);
int cur = 1;
int ok = 0;
int i = 1;
k[1] = 1;
k[0] = 0;
int st = 0;
sum += A[i][0];
while(sum >= 0)
{
if(sum - A[i][1] >= 0){
sum -= A[i][1];
if(i == k[cur] && st){
ok = 1;
st = 0;
break;
}
if(i == k[cur] && !st) st = 1;
if(i == n) i = 1;
else i++;
}
else{
if(i == n) i = 1;
else i++;
sum = 0;
k[++cur] = i;
st = 0;
if(k[cur] - k[cur-1]<= 0){
break;
}
}
sum += A[i][0];
}
printf("Case %d: ",cnt++);
if(ok) printf("Possible from station %d\n",k[cur]);
else printf("Not possible\n");
}
return 0;
}