poj3253 优先队列( poj的bug)

8月1日的题3253
3253 Fence Repair(贪心、优先队列)
(这道题看后面的算法思路)
题意:有一位农夫需要n块给定长度的木头,去借锯子时的要求是,每锯下一块,就要付出这块木头长度的费用,求最小费用。
输入:(1)n;(2)n块木头的长度;
输出:最小费用。
思路:
1、基本思路:
(1)显然要锯n次,也就是找一个最好的锯的顺序;
(2)从原题hint中看到,有一个隐含的要求是首先把需要的总长度的木头锯下来。从给的例子看,8 8 5三块。先锯下来21,然后有两种顺序,比如:8+8,剩下的自然是5,此事:21+8+8=37;另一种顺序:5+8,剩下是8,此时:21+5+8=34;显然,如果没有一开始要21的要求,用8+8+5,或5+8+8的顺序都能得到3块木头,费用一样。
2、尝试最直接的贪心:
(1)先把总和的长度cut下来;
(2)然后每次cut最小的(这样最后剩下的一块就是最长的),于是总费用最少;
(3)感觉是不是就做个最简单的排序,把最长的木头挑出来,然后其余相加,再加上总和长度,不就可以了吗?
3、网上的算法都是用优先队列,其思路是:(1)原队列中有n个,找出最小的两个求和,并对和开始累加;(2)把最小的两个从队列中拿出来,再把它们的和放进队列,重新排序,此时队列中有n-1个,总和(也就是总长度)不变;以此不断这样操作;(3)最后剩下的其实就是两个,这两个值可能不再是原来的木头的长度,而分别是一些短木头的和;
举例:需要6块木头:2 3 4 4 5 6;
(1)最后一定会得到2 3,那么得到它的方法是:需要一根5的木棍,切下2,出来2和3。这里是贪心的一个思路,要得到长为2 3的木棍,相当于我们需要一根5的木棍,同时按短的来切,这就意味着我们需要得到一根长为5的木棍,于是,要把5加入队列,把2 3从队列中去掉,于是,现在的问题变为,用最小费用来得到长为4 4 5 5 6的木棍(增加了一个5),队列为4 4 5 5 6;在这一步,记下的费用sum=2;(也就是,在新加入队列的5中切下2)
所以,这一步操作是:找最小的两个,以其中最小者记入sum,同时把和放入新队列。
(2)重复同样的操作,直到队列中只剩1个数:
考察木棍队列4 4 5 5 6:将4+4移出,将4+4=8加入队列,队列为:5 5 6 8,将4记入sum,相当于,假设有一个长为8的木棍,在这里cut4,得到4和4;sum=sum+4=6;(在新加入队列的4+4=8中切4)
考察5 5 6 8:队列变为6 8 10,在5+5中切5:sum=sum+5=11;
考察6 8 10:队列变为10 14,在6+8=14的木棍中切短6,sum=sum+6=17;
(3)队列只剩2个数,这意味着,我们需要两根长尾10和14的木棍,那么显然不必先切下24,再切下10来得到,而是直接切一个14,再切10;sum=sum+10+14=41;为最小费用;
(4)这里的方法是,n个木棍总长度比如为24,我们不需要直接切下24,而是分两次切成两个小棍,而这两个小棍的长度则是由前面的方法递推出来的。
(5)由此,切木棍的顺序为:从贪心递推,我们知道最后两个木棍长为10和14,于是先切下10和14、在14中切6、在10中切5、在8中切4、在5中切2;切的顺序为:
10 14
10 6 8;
5 5 6 8
5 5 6 4 4
2 3 5 6 4 4;

(6)如果用前面提到的最直接的贪心,结果是:24+2+3+4+4+5=42,显然不如前面的41

4、伪代码:
(1)读入n个木棍长度;
(2)排序;
(3)找最小的两个,sum=队列中最小者,然后把最小的两个移除,把和插入到队列中正确顺序;
(4)以此类推,直至只剩两个数,把这两个数分别加入sum;
5、主要会爆int,可以参考后面的用longlong
6、网上说是哈夫曼问题,但给的程序结果并不对,答案中的结果也不对,但可能这些错误结果能被poj接受,而真正正确的结果反而不被接受(有bug)
对2 3 4 4 5 6,网上的题答案都是61,正确是41
对8 5 8,网上是34,我们是26;

7知识点:
//定义从小到大的优先队列,可将greater改为less,即为从大到小
priority_queue<int, vector, greater > Q;

我的正确的代码:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int main()
{
priority_queue<long long, vector,greater > q;
int n;
scanf("%d",&n);
long long temp;
int count=n;
for(int i=0;i<n;i++)
{
scanf("%lld",&temp);
q.push(temp);
}
long long sum=0, temp1,s,t;
while(!q.empty())
{
temp1=0;
s=q.top();
q.pop();
count–;
t=q.top();
q.pop();
count–;

	if(count==0)
	{
		sum=sum+s+t;
		break;
	}	

	if(s<t)
		sum+=s;
	else
		sum+=t;
	temp1=s+t;
	q.push(temp1);
	count++;

// printf("%lld\n",sum);
}
printf("%lld\n",sum);
system(“pause”);
return 0;
}

网上被pojAC的代码:
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;

int main()
{
priority_queue<ll,vector,greater >q;
int n;
scanf("%d",&n);
ll temp;
for(int i=0;i<n;i++)
{
scanf("%lld",&temp);
q.push(temp);
}
ll sum=0;
while(!q.empty())
{
ll t=q.top();
q.pop();
if(q.empty())
break;
t+=q.top();
q.pop();
sum+=t;
q.push(t);
}
printf("%lld\n",sum);
system(“pause”);
return 0;
}

猜你喜欢

转载自blog.csdn.net/alex_yuqian/article/details/100050361
今日推荐