| 题目链接 | 难度等级 | 完成状态 | 完成分数 | 最后编辑时间 | 失误原因(初次提交分数) |
|---|---|---|---|---|---|
| 均分纸牌 | ★☆☆☆☆ | 答案正确 | 100 | 2014-10-11 16:37:59 | 看漏条件(40) |
每叠纸牌向左移或者向右移若干张算是一次移动,求使所有纸牌相等最少移动步数。
第一次居然把题目看漏了也是醉了,没看到只能移动到相邻的塔上,居然还有分过样例也是醉了。既然写了也蛮贴出来,是一个O(logn)的算法。
| 不限定相邻.cpp代码已折叠 展开折叠内容
|
|---|
#include<iostream>
#include<algorithm>
int p[101],n,average=0,count=0;
int main()
{
std::cin>>n;
for(int i=1;i<=n;++i)
{
std::cin>>p[i];
average+=p[i];
}
average/=n;
for(int i=1;i<=n;++i)
p[i]-=average;
std::sort(p+1,p+n+1);
while(p[1])
{
if(p[n]<=-p[1])
{
p[1]+=p[n];
p[n]=0;
}
else
{
p[n]+=p[1];
p[1]=0;
}
++count;
std::sort(p+1,p+n+1);
}
std::cout<<count;
return 0;
}
|
然后我们回到这题。一开始愣了很久,想不出来度娘看了两行就恍然原来做过。也是很神奇很经典的一个贪心啦。 首先先计算一下平均值,也就是最后目标每一堆要放多少,然后计算出每一堆要多还少补多少。 然后就开始移动了,明显每一堆不满足要求的都要移动,不如就从左往右开始,原因是最左边一堆只有一个来源/去路,所以很适合做开始的点。 最左边一堆无论多少只能通过右边的拿或者放,于是一次性补齐了就好。当然也可能出现右边东西不够补,但是早晚也要补,补的时间可以改变是等效的,但总是要补的,为了最优解当然要一次性补完,因此补成负数也没有关系。 右边以此类推,最左边的补齐了,就当做其不存在,直接循环下去就好了。
| 1098.cpp代码已折叠
展开折叠内容
|
|---|
#include<iostream>
int p[101],n,average=0,count=0;
int main()
{
std::cin>>n;
for(int i=1;i<=n;++i)
{
std::cin>>p[i];
average+=p[i];
}
average/=n;
for(int i=1;i<=n;++i)
p[i]-=average;
for(int i=1;i<=n;++i)
if(p[i])
{
p[i+1]+=p[i];
++count;
}
std::cout<<count<<std::endl;
return 0;
}
|