题意:
一条街上所有人都以卖酒为生,每一天有的人需要卖掉一些酒而有的人需要买入一些酒;然后在相邻的人之间运输一单位的酒需要一单位的花费,问怎么样安排人们之间的交易,可以使得总运算费用最小。
思路:
开始就想到一个贪心思路:显然每个需要买酒的人都应该尽量买他最左边卖的酒,没有的话再买他右边最近卖酒人的酒。第二点很好理解,现在来解释一下第一点:如果当前这个人不买他最左边人卖的酒而那些酒反正都是要卖出去的,这些酒就要由他右边的人买,那么这些酒卖出的代价就必然变大。
具体实现时我们需要判断每个人的左边是不是还有可以买的酒,这样如果直接通过循环进行判断的话是一定会超时的(我开始就这样写了一次,结果就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;
}