uva--11054Wine trading in Gergovia +贪心

题意:

一条街上所有人都以卖酒为生,每一天有的人需要卖掉一些酒而有的人需要买入一些酒;然后在相邻的人之间运输一单位的酒需要一单位的花费,问怎么样安排人们之间的交易,可以使得总运算费用最小。

思路:

开始就想到一个贪心思路:显然每个需要买酒的人都应该尽量买他最左边卖的酒,没有的话再买他右边最近卖酒人的酒。第二点很好理解,现在来解释一下第一点:如果当前这个人不买他最左边人卖的酒而那些酒反正都是要卖出去的,这些酒就要由他右边的人买,那么这些酒卖出的代价就必然变大。

具体实现时我们需要判断每个人的左边是不是还有可以买的酒,这样如果直接通过循环进行判断的话是一定会超时的(我开始就这样写了一次,结果就TL了);实际上我们可以另用一个数组记录所有卖酒人的坐标,这样我们每次都只需要扫描这个数组就行了(这个数组开始的元素必定是最左边买酒人的坐标),如果这个数组前面的项对应的酒量变成0,我们就把开始坐标右移(如果没有这一步,就肯定会超时)。

但是刚才在网上看到另一种做法,就是不考虑题目中规定的买卖关系,规定第i个人买第i+1个人的酒,这样答案是对的,但是一下还是想不清楚原理。

代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;

#define LL long long

int main()
{
    int i,j,k,n,a[110000],b[110000],left;
    while(scanf("%d",&n)&&n)
    {
         LL sum=0; k=0;
         for(i=0;i<n;i++)
         {
              scanf("%d",&a[i]);
              if(a[i]<0)
                b[k++]=i;
         }
         left=0;
         for(i=0;i<n;i++)
         {
             if(a[i]>0)
             {
                 for(j=left;j<k;j++)
                 {
                     if(a[b[j]]+a[i]<=0)
                     {
                         sum+=a[i]*abs(b[j]-i);
                         a[b[j]]+=a[i];
                         a[i]=0;
                         if(a[b[j]]==0)
                            left++;
                         break;
                     }
                     else
                     {
                         sum+=-1*a[b[j]]*abs(b[j]-i);
                         a[i]+=a[b[j]];
                         a[b[j]]=0;
                         left++;
                     }
                 }
             }
         }
         printf("%lld\n",sum);
    }
 return 0;
}

另一种方法的代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;

#define LL long long

int main()
{
    int i,j,k,n,a[110000],b[110000],left;
    while(scanf("%d",&n)&&n)
    {
         LL sum=0; k=0;
         for(i=0;i<n;i++)
              scanf("%d",&a[i]);
        for(i=0;i<n-1;i++)
        {
               sum+=abs(a[i]);
               a[i+1]+=a[i];
        }
         printf("%lld\n",sum);
    }
 return 0;
}
时间: 2024-10-07 06:09:57

uva--11054Wine trading in Gergovia +贪心的相关文章

UVA-11054-Wine trading in Gergovia(模拟+贪心)

首先这道题的节点数太多了,达到10^5,所以不能用数组模拟啊,肯定TLE,所以用贪心算法,读取第一个结点,搬到第二个结点,剩下的和第二个结点合并,一起搬到第三个结点......这个算法很好,每次看成只是邻居间买卖,下面是代码: #include<stdio.h> #include<iostream> #include<stdlib.h> using namespace std; int main() { int n; while(cin>>n &&a

UVa 11054 Wine trading in Gergovia(扫描)

题意  有n个村庄  第i个村庄需要买a[i]的酒   a[i]为负时该村庄可卖掉-a[i]的酒  保证所有a[i]的和为0   一个单位的酒从一个村庄运输到相邻村庄的消耗为1  求运输完所有酒需要的最小消耗 总消耗最少时  每个需要买的村庄都会找离他最近的可以卖的村庄  容易发现  这种状况下  从第一个村和第二个村庄之间的运输量为abs(a[1])  第二个村庄和第三个村庄之间的运输量为abs(a[1]+a[2])   第k个村庄到第k+1个村庄的运输量为abs(a[1]+a[2]+...+

uva 1521 - GCD Guessing Game(贪心)

题目链接:uva 1521 - GCD Guessing Game 题目大意:给定一个数N,现在又一个数x,在1~N之间,现在每次可以猜一个数a,返回gcd(x,a),问说最少猜几次可以确定x. 解题思路:其实就将1~N里面的素数都要考虑一遍,因为有一个N的限制,所以每次选出来的素数的积不大于N即可. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const

uva 10026 Shoemaker&#39;s Problem(贪心+排序)

虽然是个水题,但是在一些细节上wa了几次,好像不支持'\b'退格符号,我用在了输出空格那,结果wa了...白白 wa了几次...题意是看的题解..今天只写了两道题,速度有点慢,得加快了,以后得先认真读懂题目,题目读懂了 就相当于做出来一半然后仔细动脑想想,有想法了再敲,不能盲目的做题.另外,热烈祝贺今天c++ primer看到 了100页 思路: 这道题是让给的数据是每件工作需要做的天数和每耽误一天所需要的费用,让求一个序列使得付费最小,如果有相同答 案把字典树最小的输出...输出的是序号,该件

uva 1016 - Silly Sort(置换+贪心)

题目链接:uva 1016 - Silly Sort 题目大意:给定一个长度为n的序列,每次操作可以交换任意两个数的位置,代价为两个数的和,求最小代价,将序列排成有序的. 解题思路:给定序列根据数的大小映射成一个置换,分解置换的循环,对于每个循环中,肯定是用值最小的逐个去交换的代价最小,但是要考虑,可以将最小的值与序列中最小值交换,用它代替去交换,最后再换回来.取两种情况中最优的. #include <cstdio> #include <cstring> #include <

uva 714 - Copying Books(贪心 最大值最小化 二分)

题目描述开头一大堆屁话,我还仔细看了半天..其实就最后2句管用.意思就是给出n本书然后要分成k份,每份总页数的最大值要最小.问你分配方案,如果最小值相同情况下有多种分配方案,输出前面份数小的,就像字典序输出从小到大一样的意思. 这里用到贪心的方法,定义f(x)为真的条件是满足x为最大值使n本书分成k份,那么就是求x的最小值.如何确定这个x就是用的二分法,x一定大于0小于所有值的合,不断的二分再判断是否成立,成立就取左半边,不成立说明太小了就取右半边,写的时候还是没有把二分法理解透彻,我还怕会丢失

uva:10670 - Work Reduction(贪心)

题目:10670 - Work Reduction 题目大意:给出n, m, L.n代表老板给的全部的paperworks的数量,m代表最终剩下的数量,L代表由这么多家公司需要你来计算最小的花费. 解题思路: 1.L家公司l行.每行由公司的名字 :A,B: A代表一份paperwork需要的money,B则代表帮你减少到总共的paperworks的数量一半要话费的money.注意这里是你手头上有的paperworks而不是老板要求你完成的数量,之前在这里卡了好久.还有减半不能导致最终的数量小于m

uva:10602 - Editor Nottoobad(贪心)

题目:10602 - Editor Nottoobad 题目大意:有一个机子它由press的动作还有copy和delete字符的动作.给一组字符串,问要输入这样的一组字符串,最少要执行的press动作. 解题思路:将这一组字符串按照ascall码排序后,这样前后两个字符串的相似度是比较高的.然后后一个字符串和前一个字符串相比,看有多少相同的可以copy,就只要统计一下不相同的字符个数.这题比较迷惑人的是题目一直说要求第一个字符串一定要先执行press动作,但是输出却可以任意给一种,不一定是要第一

UVA 1379 - Pitcher Rotation(DP + 贪心)

题目链接:1379 - Pitcher Rotation 题意:n个人,m个敌人,去比赛,有得分,n个人可以重复比,但是每次比完要休息4天,问最大得分 思路:dp[i][j][k][l][x] 表示第场比赛,前一天为j,两天为k,三天为l,四天为x,的最大得分,然后由于只有每个人5天就能用一次,所以对于每个人来说,只有得分前5的会被使用上,所以后4维状态只需要5^4,进行状态转移,不用比赛的情况分开考虑,还有这题内存有限,要用滚动数组优化不然会RE 代码: #include <stdio.h>