149 丝雨姐的入门day1枚举贪心 I题 枚举初值问题 好题

HDU 5353

要求:n个人围成一圈,每个人有若干个糖果,相邻的两人之间只可进行1次操作:A给B一个糖果、B给A一个糖果或不给糖果。问是否能使每个人糖果数相同。

方法:设置初值进行枚举。

1.首先看这题不好操作,因为每个人可向左操作也可向右操作。

2.一次循环从左到右判断两个人之间进行什么操作,这样一次循环就包括了一个人与左右两个人的操作,假设B左边是A,B右边是C,不好判断B与A和B与C进行什么操作,先分析A与B,再分析B与C即可。

3.第2步需要一个初值才能启动判断,假设从第1个人开始判断,因为第1个人和第2个人、第n个人均有操作的可能,所以开始无法判断第1个人和第2个人进行什么操作,但是第1个人和第2个人之间只有三种操作的可能。枚举3种可能作为第1个人和第2个人的操作初值,因此左边处理过了,依次向右判断。

4.重点是初值的枚举!!!!!!

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;
long long a[100001],b[100001];
struct ab
{
 int x,y;
};
ab cd[100001];
int main()
{
 int t,n,i,j,k,flag;
 long long sum1,aver,cnt,max1;
 scanf("%d",&t);
 while(t--)
 {
  scanf("%d",&n);
  sum1=0;
  max1=-1;
  for(i=0;i<n;i++)
  {
   scanf("%d",&a[i]);
   sum1+=a[i];
   max1=max(max1,a[i]);	
  }
  if(double(sum1)/double(n)!=sum1/n)
  {
   printf("NO\n");
   continue;	
  }
  aver=sum1/n;
  if(max1==aver)
  {
   printf("YES\n0\n");
   continue;	
  }
  for(k=-1;k<=1;k++)
  {
   memcpy(b,a,sizeof(a));
   flag=1;
   cnt=0;
   b[0]-=k;
   b[1]+=k;
   if(k==1) 
   {
   	cd[cnt].x=1;
   	cd[cnt].y=2;
   	cnt++;
   }
   if(k==-1)
   {
   	cd[cnt].x=2;
   	cd[cnt].y=1;
   	cnt++;
   }
   for(i=1;i<n;i++)
   {
    if(b[i]==aver) continue;
    else if(b[i]-aver>0)
    {
   	 b[i]-=1;
   	 b[(i+1)%n]+=1;
   	 cd[cnt].x=i+1;
   	 cd[cnt].y=(i+1)%n+1;
   	 cnt++;
    }
    else if(b[i]-aver<0)
    {
   	 b[i]+=1;
   	 b[(i+1)%n]-=1;
   	 cd[cnt].x=(i+1)%n+1;
   	 cd[cnt].y=i+1;
     cnt++;
    }
   }
   for(i=0;i<n;i++)
   if(b[i]!=aver) flag=0; 
   if(flag) break;
  }
  if(!flag) 
  {
   printf("NO\n");
   continue;	
  }
  printf("YES\n");
  printf("%d\n",cnt);
  for(i=0;i<cnt;i++) 
   printf("%d %d\n",cd[i].x,cd[i].y); 
 }
}

猜你喜欢

转载自blog.csdn.net/Irving0323/article/details/81671103