北大ACM——4014,Dice(贪心)

题意:有n个骰子,第i个有a[i]个面。对于骰子上的数字,应从1~m当中选择刻画到每个骰子的每一面,且每个数字只许用一次,其中m=Σa[i]。你的任务是求出一种数字安排,使得 每个骰子 所投出来的数字的数学期望 之和 E最大,要求输出E并输出第i个骰子的数字安排。

分析:这道题最后一句,要求输出每个骰子的数字安排,意味着你不能打乱每个骰子的序号,面对这种情况,应采用结构体,在结构体中增加一个成员记录下序号,这样一来就可以确保骰子的序号不被打乱。
贪心策略:首先,设置结构体struct dice,包含face,num两个成员,一开始按d[i].face从小到大排序,优先为d[i].face小的安排大数字,最后按d[i].num从小到大排序,即排回初始顺序,便于输出数字安排

伪代码如下:
struct dice
{
double face;
int num;
}d[1005];
double e[1005];
void sort1;
void sort2;
int main()
{
int n,i,j,k;
double m=0,sum=0;
scanf("%d",&n);
for(i=0;i<=n-1;i++){
输入d[i].face;
d[i].num=i;
m+=d[i].face;
}
sort1,按d[i].face从小到大排序;
for(i=0;i<=n-1;i++){
e[d[i],num]=(m+m-d[i].face+1)/2.0;
sum+=e[d[i].num];
m=m-d[i].face;
}
sort2,按d[i].num从小到大排序(即,重新排回初始顺序)
输出sum;
for(i=0;i<=n-1;i++){
j=e[i]-(d[i].face-1)/2.0;
k=j+d[i].face-1.0;
while(j<=k){
输出数字安排
}
}
代码如下:

#include<cstdio>
using namespace std;
struct dice
{
	double face;   //face表示有多少个面
	int num;    //num表示序号
}d[1005];
double e[1005];   //e[]用于记录每个骰子对应的数学期望;
void sort1(int n)
{
	int i,j,k;
	for(i=0;i<=n-2;i++)
	{
		k=i;
		for(j=i+1;j<=n-1;j++)
		{
			if(d[k].face >d[j].face ) k=j;
		}
		if(k!=i)
		{
			struct dice t; 
			t=d[i];d[i]=d[k];d[k]=t;  //同类的结构体可以直接互相赋值
		}
	}
 } 
void sort2(int n)
{
	int i,j,k;
	for(i=0;i<=n-2;i++)
	{
		k=i;
		for(j=i+1;j<=n-1;j++)
		{
			if(d[k].num >d[j].num ) k=j;
		}
		if(k!=i)
		{
			struct dice t;
			t=d[i];d[i]=d[k];d[k]=t;
		}
	}
}
int main()
{
	int n,i,j,k;
	double m=0,sum=0;
	scanf("%d",&n);
	for(i=0;i<=n-1;i++)
	{
		scanf("%lf",&d[i].face);
		d[i].num=i;      //把序号存入结构体,这样不论怎么折腾,只要不去动d[i].num的值,每个dice的序号就不会改变
		m+=d[i].face;
	}
	sort1(n);
	for(i=0;i<=n-1;i++)
	{
		e[d[i].num]=(m+m-d[i].face+1.0)/2.0;  //利用等差数列求和公式,化简后就是这条式
		sum+=e[d[i].num];   //sum记录数学期望的总和
		m=m-d[i].face;
	}
	sort2(n);
	printf("%.5lf\n",sum);   
	for(i=0;i<=n-1;i++)
	{ //其实一开始是想着用数组来记录数字安排,但那样做太耗空间了,而且不方便。事实上也没有必要,根据等差数列求和公式,我们就可以算出首项和末项了
		j=e[i]-(d[i].face-1.0)/2.0; //j为首项
		k=j+d[i].face-1.0;  //k为末项
		while(j<=k)  
		{
			if(j!=k) printf("%d ",j++);
			else printf("%d\n",j++);
		}
	}
	return 0;
}

小结:
1.当题中要求不可打乱数据的次序时,可考虑结构体,在结构体中引入序号成员;
2.当题中涉及到等差数列时,可利用等差数列的性质(一般为求和公式的应用),简化解题过程。

这道题对我个人而言是挺有意义的,因为之前遇到这种不可乱序号的题就没辙,但是这次突然想到可以用结构体来解决,就AC出来了。不过有点怪的地方就是,第一次提交用G++是WA,第二次提交用C++就AC了,其它什么也没有改变。因此,以后如果AC不过,也有可能是这种情况。
怪的原因已经找出:G++与C++的double类型输出格式不同,前者是"%f”,后者是“%lf”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值