海盗分金币

问题描述


      有n个海盗,得到了m个金币。他们决定将之瓜分。分的方法是站成一排,从1号到n号海盗依次提出方案。如果提出的方案得到的支持人数比例超过Q%(0<=Q<100),那么就通过方案,进行分配,提出方案的海盗也有投票权。否则就把提出方案的人扔到海里喂鲨鱼。
海盗都是精明的,他们能够分析出如何最大化自己的利益。

海盗是贪婪的,总是选择更大的利益。

海盗是邪恶的,如果利益相同,更愿意杀人。

输入n,m,Q,问第一个人最多可能得到多少金币。如果必死无疑,输出-1.

n<=10000, m<=1000000000

样例解析:

当有一个人的时候,他能够拿到所有的100个金币。

当有两个人的时候,后一个人永远不会同意前一人的方案,即必死无疑,等于-1。

当有三个人的时候,第一人选择自己拿走100个,其他人不给。此时第二人如果不支持,就必死,故一定会支持。

当有四、五个人的时候,分配方案如下:

1个人:100
2个人:100  -1
3个人:  0   0 100
4个人:  1   1   0  98
5个人:  2   0   1   0  97


测试输入关于“测试输入”的帮助 期待的输出关于“期待的输出”的帮助 时间限制关于“时间限制”的帮助 内存限制关于“内存限制”的帮助 额外进程关于“{$a} 个额外进程”的帮助
测试用例 1 以文本方式显示
  1. 5 100 50↵
以文本方式显示
  1. 97↵
1秒 64M 0
题解思路

大致思路;

      因为每个人都是聪明绝顶的,并且是残忍的,所以第一个人知道后面所有人的方案,所以第一个人要想使自己的方案被采纳就必须要贿赂其他的n*p/100个人才行。贿赂的时候就找最好贿赂的人进行贿赂。

具体实现:

      从1个人递推到n个人,对于每一次的递推,先判断新加入的人是否会死,然后如果不会死的话就将要贿赂的人的期望加1,其他的人的期望赋为0,然后排序,将期望小的放在最前面方便下一次贿赂。

注意:

      由于时间限制,所以排序的时候需要注意。我们在排序的时候发现,每次需要排序的都是两个有序的序列,所以我们只需要把这两个序列交换一下位置就可以了,这样从1开始每次都是这样有序排的,可以节省很多时间。


实现代码


<span style="font-family:Microsoft YaHei;font-size:14px;">#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
   int n,q;
  long m;
   int i,huilu,sum,j,temp1,temp2,k,l;
   int a[10001];
   memset(a,0,sizeof(a));
   scanf("%d%d%d",&n,&m,&q);
   if(n==1)
   {
   	printf("%d\n",m);
   }
   else
   {
   	for(i=1;i<=n;i++)
   	{
   	   huilu=0;
   	   sum=0;
   	   if(i==1)
   	   {
   	   	a[0]=m;
   	   }
		else if(i!=n)
		{
			huilu=i*q/100;
			for(j=1;j<=huilu;j++)
			{
				sum+=a[j-1]+1;
			}
			if(sum>m)
			{
				for(k=0;k<i-1;k++)
				{
					a[i-1-k]=a[i-2-k];
				}
				a[0]=-1;
			}
			else
			{
				for(j=1;j<=huilu;j++)
				{
					a[j-1]=a[j-1]+1;
				}
				for(k=1;k<=huilu;k++)
				{
					a[i-1-k]=a[huilu-k];
				}
				for(j=huilu+1,k=0;j<i;j++,k++)
				{
					a[k]=0;
				}
				a[i-1]=m-sum;
				temp1=a[i-1];
				for(k=i-2;k>0;k--)
				{
					if(a[k]<=temp1)
					{
						for(l=i-2;l<=k+1;l++)
						{
							a[l+1]=a[l];
						}
					    a[k+1]=temp1;
						break;	
					}	
				}
			}
		}
		else
		{
			huilu=i*q/100;
			for(j=1;j<=huilu;j++)
			{
				sum+=a[j-1]+1;
			}
			if(sum>m)
			{
				printf("-1\n");
			}
			else
			{
				for(j=1;j<=huilu;j++)
				{
					a[j-1]=a[j-1]+1;
				}
				for(k=1;k<=huilu;k++)
				{
					a[i-1-k]=a[huilu-k];
				}
				for(j=huilu+1,k=0;j<i;j++,k++)
				{
					a[k]=0;
				}
				a[i-1]=m-sum;
				temp2=a[i-1];
				for(k=i-2;k>0;k--)
				{
					if(a[k]<=temp1)
					{
						for(l=i-2;l<=k+1;l++)
						{
							a[l+1]=a[l];
						}
					    a[k+1]=temp2;
						break;	
					}	
				}
				printf("%d\n",a[n-1]);
			}	
		}
			
   	}
   }
   return 0;	
}</span>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值