UVA - 11054 Wine trading in Gergovia 【贪心(等价转换)】

题目链接:https://cn.vjudge.net/problem/UVA-11054

题意:

每个房子里的人,要么要买酒要么要卖酒,保证所有卖酒的量和买酒的量之和为0,也就是供应量一定是足够的;一桶酒运到一个相邻的房子要一个劳动力,问最少要多少劳动力才能完成运送任务;

思路:(codeforces div2 的ABC很多都是这样的题)

第一种:从第一个开始,如果想要卖酒,那么就从当前位置开始找最近的需要买酒的人,如果买酒的量能够满足卖酒的,就从第二个开始遍历;如果不满足,就继续找下一个买酒的人,直到当前的值为0;(先暂且不看题目是怎么问你问题的,只要知道一点,就是当满足题目要求的时候,所有给出的值到最后都会变成0,所以,我们只需要考虑如何把每一个房子的对应的需求量变成0就行了,因为步数跟消耗的劳动力有关系,求最小,那肯定是优先看最近的,因为第一个值只能通过右边的值归0,所有优先把第一个变成0,那么第二个就跟第一个是一样的状态了,也是只能通过右边的值归0);

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<sstream>
#include<vector>

using namespace std;

#define IOS ios::sync_with_stdio(false); cin.tie(0);

typedef long long ll;
const int Maxn = 1e5+10;
const long long LINF = 1e18;
const int INF = 0x3f3f3f3f;

int a[Maxn];

int main (void)
{
    int n;
    while (scanf("%d",&n) != EOF) {
        if(!n) break;
        for (int i = 1; i <= n; ++i) {
            scanf("%d",&a[i]);
        }
        ll res = 0;
        int tmp;
        for (int i = 1; i < n; ++i) {
            if(a[i] == 0) continue;
            tmp = a[i];
            if(tmp < 0) {
                for (int j = i+1; j <= n; ++j) {
                    if(a[j] > 0) {
                        if(tmp+a[j] < 0) {
                            tmp+=a[j];
                            a[j] = 0;
                        } else {
                            a[j]+=tmp;
                            tmp = 0;
                        }
                        res+=(j-i)*abs(a[i]-tmp);
                        a[i] = tmp;
                        if(tmp == 0) break;
                    }
                }
            }
            else if(tmp > 0) {
                for (int j = i+1; j <= n; ++j) {
                    if(a[j] < 0) {
                        if(tmp+a[j] > 0) {
                            tmp+=a[j];
                            a[j] = 0;
                        } else {
                            a[j]+=tmp;
                            tmp = 0;
                        }
                        res+=(j-i)*abs(a[i]-tmp);
                        a[i] = tmp;
                        if(tmp == 0) break;
                    }
                }
            }
        }
        printf("%lld\n",res);
    }
    return 0;
}

 

第二种(紫书的方法):

第一个房子不管是买酒还是卖酒,来源或者运出去一定通过第二个房子,不管这些酒是不是第二个房子产的或者是第二个房子需要的;比如说,第一个房子要买酒,假设最优的方法是取第三个房子的酒,那么运输的过程中,是不是一定会经过第二个房子?所以我不管第一个房子是卖酒还是买酒,我直接把需求量全部丢给第二个房子,那么第二个房子有可能会从卖酒变成买酒也可能仍然是卖酒,如果第二个房子能正好满足需求就最好,如果不能就继续把需求丢给第三个房子,到最后,所有的值都会变成0,而且每一步都只运输一个房子,我们要做的就是把多余的,丢出去的需求量加起来就行了,这样遍历一次,就能把每一个都值都归0;

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<sstream>
#include<vector>

using namespace std;

#define IOS ios::sync_with_stdio(false); cin.tie(0);

typedef long long ll;
const int Maxn = 1e5+10;
const long long LINF = 1e18;
const int INF = 0x3f3f3f3f;

int main (void)
{
    int n;
    while (cin >> n && n) {
        ll ans = 0, a, last = 0;
        for (int i = 0; i < n; ++i) {
            cin >> a;
            ans+=abs(last);
            last+=a;
        }
        cout << ans << endl;
    }
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值