Comparison of two questions using greedy algorithms (selling wine problem Uva 11054 and circular runway Uva 11093)

Uva 11054 Link

Uva 11054 emphasizes labor (not wine), labor cannot be offset, and must be added up (whether it is in or out), and if it is negative, the absolute value is used . I understand that the labor force here is equivalent to the internal friction of the system. We can regard a village or multiple villages together as a village, but at the same time we must add the internal friction of its system.

Example:
a[5] = {2,3,-4,-2,1} //sum of a[i]=0
The labor required for 2,3,-4,-2,1 is equivalent to 5, -4,-2,1 required labor +2
5,-4,-2,1 required labor is equivalent to 1,-2,1 required labor +5
1,-2,1 required labor The labor force is equivalent to the labor force required for -1,1 +
1 The labor force required for -1,1 is equivalent to the labor force required for 0 + 1 (absolute value)
so the total labor force is 2+5+1+1=9.

The code is as follows (refer to Zishu's answer, example 8-5):

long long WineLabor(long long a[], int len) {
     long long last, ans;

     for (int i=0; i<len; i++) {
         ans += abs(last);
         last += a[i];
     }
     return ans;
}

The ans is the required cumulative labor force. If a[5]={2,3,-4,-2,1}, the values ​​of ans are 0,2,7,8,9 respectively. last is the sum of a[i] and its value is 2,5,1,-1,0.
Note:
1) The labor force of n villages is calculated n-1 times. We only need to calculate ans to a[n-2], which is the second-to-last element. Because the labor between the penultimate village and the penultimate village can be counted once. For example, the a[i] value of the last 2 villages is [-3, 3], it can be seen that 3 labors are required.
2) This question also has a ring variant UVA - 11300 Spreading the Wealth. Write it down and do it later.

Uva 11093 link

In Uva 11093, the car refuels x1 at each gas station first, then consumes x2, and the net remains x1-x2. In this question, each gas station enters and exits, just calculate the net residual value (note that it is different from Uva11054), not the sum of absolute values.

Note:
1) This question has a ring, you can use i=(i+1)%n, or you can expand a ring into two rings to operate like a linked list.

Method 1: One ring becomes two rings. (Refer to https://menyifan.com/2015/10/18/uva11093/ )

#include <iostream>

using namespace std;

const int maxn=100000+5;
int n, p[maxn], q[maxn];


int travel(int p[], int q[], int n) {
    int finish = 0;
    int ans = -1;
    for (int start=0; start<n; start=finish) {
        finish = start;
        int fuel = 0, sum = 0;
        while ((ans<0) && (fuel>=0)) {
            fuel+=p[finish]-q[finish];
            finish++;
            sum++;
            if ((sum==n) && (fuel>=0))
                ans=start;
        }

        if (ans>=0)
            return ans+1;   //因为下标从0开始算
    }

    return ans;
}

int main()
{
    int T;
    scanf("%d", &T);
    for (int k=1; k<=T; k++) {
        scanf("%d", &n);
        for (int i=0; i<n; i++) {
            scanf("%d", &p[i]);
            p[i+n]=p[i];
        }
        for (int i=0; i<n; i++) {
            scanf("%d", &q[i]);
            q[i+n]=q[i];
        }

        int ans = travel(p,q,n);
        printf("Case %d: ", k);
        if(ans < 0)
            cout<<"Not possible"<<endl;
        else
            cout<<"Possible from station "<<ans<<endl;
    }
    return 0;
}

Note the condition of while(). Fuel>=0 must be used here, but sum<=n cannot be used. Otherwise, while() will continue when fuel < 0 in the middle, which will make an unqualified site go toe-to-toe.
For example:
input p[] = {1,3,1,4,2,1,2,3,2}
input q[] = {2,2,1,3,1,3,1,1,1}
When start = 0, debug is as follows
start=0 finish=0 fuel=0
start=0 finish=1 fuel=-1 //here while() will still continue
start=0 finish=2 fuel=0
start=0 finish= 3 fuel=0
start=0 finish=4 fuel=1
start=0 finish=5 fuel=2
start=0 finish=6 fuel=0
start=0 finish=7 fuel=1
start=0 finish=8 fuel=3
find !start=0 finish=9
Case 1: Possible from station 1

Method 2: Still use the classic i = (i+1)%n. This is also the solution of Zishu. Note that when the output ans is greater than the starting site, it means that it has been wrapped, that is, there is no solution.
code show as below:


int travel2(int p[], int q[], int n) {

    int start = 0, finish =0, fuel = 0;
    while(1) {
        //重新开始
        finish = start+1;
        fuel = p[start] - q[start];
        while (finish != start) {   //no wrap,注意这里不可以用finish > start, 否则wrap后自动退出
            if ((fuel < 0))
                break;
            fuel += p[finish] - q[finish];
            finish = (finish + 1) % n;
        }

        if (finish > start)
            start = finish;
        else if (finish < start)
            return -1;
        else //finish == start, 走完一圈,但是还是要看fuel
            if (fuel >= 0)
                return finish + 1; //因为下标从0开始算
            else
                return -1;
    }
}

Note that the complexity of the above two methods is O(n). Because although there are two loops nested, each site is counted only once.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325640849&siteId=291194637