题意:环形跑道上有n n<=100000 个加油站 编号为1-n 第i个加油站可以加油pi加仑 从加油站i开到下一站需要qi加仑 你可以选择一个加油站作为起点 初始油箱为空 如果可以走完一圈 那么输出最小的起始站点 否则输出-1
如果 对每个加油站作为起始点进行枚举的话 那么复杂度为 n^2
其中有一个重要的思路可以优化:
比如从第一个点最为起始点 如果能走一圈 那么就成了 第一个也为最小起始点
如果 走到t点 t到t+1走不了 那么 第2个点到 第t个点作为起始点 都是一定不可行的!!
接下来就将t+1作为起始点再次尝试遍历
#include<bits/stdc++.h> using namespace std; #define N 100001 int vis[N]; int p[N],q[N];//p为加油 q为油耗 int n; int go(int start) { int oil=p[start]-q[start]; if(oil<0) return start; for(int i=(start+1)%n; i!=start;i=(i+1)%n ) { oil+=p[i]-q[i]; if(oil<0)return i; } return N; } int solve(void) { int start=0; memset(vis,0,sizeof vis); vis[0]=1; for(;;) { int e=go(start); if(e==N)return start; start=e+1; if(vis[start])return -1; vis[start]=1; } } int main() { int cas;cin>>cas; for(int kase=1;kase<=cas;kase++) { cin>>n; for(int i=0;i<n;i++)scanf("%d",&p[i]); for(int i=0;i<n;i++)scanf("%d",&q[i]); int ans=solve(); printf("Case %d: ",kase); if(ans==-1)printf("Not possible\n"); else printf("Possible from station %d\n",ans+1); } return 0; }
LRJ的代码更快更巧妙!
// UVa11093 Just Finish it up // Rujia Liu #include<cstdio> const int maxn = 100000 + 5; int n, p[maxn], q[maxn]; // returns s if success // otherwise, return the station you failed to reach // if you failed to reach the start, return -1 int go(int s) { int fuel = p[s] - q[s]; for(int i = (s+1)%n; i != s; i = (i+1)%n) { if(fuel < 0) return i; fuel += p[i] - q[i]; } if(fuel < 0) return -1; // this means sum(p) < sum(q), so this case is impossible return s; // success } int solve() { int start = 0; for(;;) { int finish = go(start); if(finish < start) return -1; // wrapped around, or go(start) returns -1 if(finish == start) return start; start = finish; } } int main() { int T; scanf("%d", &T); for(int kase = 1; kase <= T; kase++) { scanf("%d", &n); for(int i = 0; i < n; i++) scanf("%d", &p[i]); for(int i = 0; i < n; i++) scanf("%d", &q[i]); int ans = solve(); printf("Case %d: ", kase); if(ans < 0) printf("Not possible\n"); else printf("Possible from station %d\n", ans+1); } return 0; }