描述
有 N 堆纸牌,编号分别为 1,2,…, N。每堆上有若干张,但纸牌总数必为 N 的倍数。可以在任一堆上取若于张纸牌,然后移动。
移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 的堆上;在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。
现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。
例如 N=4,4 堆纸牌数分别为:
① 9 ② 8 ③ 17 ④ 6
移动3次可达到目的:
从 ③ 取 4 张牌放到 ④ (9 8 13 10) -> 从 ③ 取 3 张牌放到 ②(9 11 10 10)-> 从 ② 取 1 张牌放到①(10 10 10 10)。
格式
输入格式
N(N 堆纸牌,1 <= N <= 100)
A1 A2 … An (N 堆纸牌,每堆纸牌初始数,l<= Ai <=10000)
输出格式
所有堆均达到相等时的最少移动次数。
样例1
样例输入1
4
9 8 17 6
样例输出1
3
限制
每个测试点1s
来源
NOIP2002提高组第一题
题解
简单题 算出平均数以后直接加加减减 写这个题的目的不是这个
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int a[150];
int main(){
int n,sum=0,tot;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
tot=sum/n;int ans=0;
for(int i=1;i<=n;i++)
{
if(a[i]==tot) continue;
ans++;
a[i+1]+=a[i]-tot;
}
printf("%d",ans);
return 0;
}
目的是另一种做法:
费用流。。
(noip本来就不考网络流 而且这么简单的noip提高组第一题用什么费用流,还几乎搞了一下午真是浪费时间)
感觉可以写就写了试试 此题和网络流24题里面的负载平衡问题差不多
结果发现因为 这里的费用是每一次才加1 而且如果有重复的情况不好处理(看样例就行 此代码过不了样例。。。)
在这里提供一种思路 如果哪位大神看到这个博客 可以改进我的代码请留言或QQ我
虽然这个做法不行,但是因为数据水的问题还是 得(混)了40分
//因为费用流过程中 每次找到一个最短路 但是有些操作时重复 所以无法通过
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define inf 0x7ffffff
using namespace std;
struct node{int to,next,flow,cost;}e[1000005];
int start,end,flag[1005],d[1005],from[1005],head[1005],a[150],mp[300][300];
queue<int>q;int cnt=1;int min_cost;
void ini(int x,int y,int flow,int cost){e[++cnt].to=y;e[cnt].flow=flow;e[cnt].cost=cost;e[cnt].next=head[x];head[x]=cnt;}
void insert(int x,int y,int flow,int cost){ini(x,y,flow,cost);ini(y,x,0,-cost);}
bool spfa(){
memset(d,127,sizeof(d));
d[start]=0;
q.push(start);flag[start]=1;
while(!q.empty()){
int k=q.front();q.pop();flag[k]=0;
for(int i=head[k];i;i=e[i].next){
int kk=e[i].to;
if(e[i].flow&&d[kk]>d[k]+e[i].cost)
{
d[kk]=d[k]+e[i].cost;from[kk]=i;
if(!flag[kk]){
flag[kk]=1;
q.push(kk);
}
}
}
}
return d[end]<inf;
}
void mcf(){
while(spfa()){
int mn=inf;
for(int i=from[end];i;i=from[e[i^1].to]){
mn=min(mn,e[i].flow);//printf("%d ",e[i].to);
}
min_cost+=d[end];
for(int i=from[end];i;i=from[e[i^1].to]){
e[i].flow-=mn;e[i^1].flow+=mn;
}//printf("\n");
}
}
int main(){
int n,sum=0,tot;
start=0,end=1001;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum+=a[i];
}
tot=sum/n;
for(int i=1;i<=n;i++)
a[i]-=tot;
for(int i=1;i<=n;i++){
if(a[i]>0) insert(start,i,a[i],0);
else if(a[i]<0) insert(i+n,end,-a[i],0);
if(i!=n){
insert(i,i+1,inf,1);
insert(i,i+1+n,inf,1);
}
if(i!=1)
{
insert(i,i-1,inf,1);
insert(i,i-1+n,inf,1);
}
//insert(i+n,i,inf,0);
}
mcf();
printf("%d",min_cost);
return 0;
}