10
22
2015
0

【poj3253】【USACO 2006 Nov】【贪心法】【优先队列】Fence Repair

Fence Repair
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 33487 Accepted: 10786
Description
 
Farmer John wants to repair a small length of the fence around the pasture. He measures the fence and finds that he needs N (1 ≤ N ≤ 20,000) planks of wood, each having some integer length Li (1 ≤ Li ≤ 50,000) units. He then purchases a single long board just long enough to saw into the N planks (i.e., whose length is the sum of the lengths Li). FJ is ignoring the "kerf", the extra length lost to sawdust when a sawcut is made; you should ignore it, too.
 
FJ sadly realizes that he doesn't own a saw with which to cut the wood, so he mosies over to Farmer Don's Farm with this long board and politely asks if he may borrow a saw.
 
Farmer Don, a closet capitalist, doesn't lend FJ a saw but instead offers to charge Farmer John for each of the N-1 cuts in the plank. The charge to cut a piece of wood is exactly equal to its length. Cutting a plank of length 21 costs 21 cents.
 
Farmer Don then lets Farmer John decide the order and locations to cut the plank. Help Farmer John determine the minimum amount of money he can spend to create the N planks. FJ knows that he can cut the board in various different orders which will result in different charges since the resulting intermediate planks are of different lengths.
 
Input
 
Line 1: One integer N, the number of planks 
Lines 2..N+1: Each line contains a single integer describing the length of a needed plank
Output
 
Line 1: One integer: the minimum amount of money he must spend to make N-1 cuts
Sample Input
 
3
8
5
8
Sample Output
 
34
Hint
 
He wants to cut a board of length 21 into pieces of lengths 8, 5, and 8. 
The original board measures 8+5+8=21. The first cut will cost 21, and should be used to cut the board into pieces measuring 13 and 8. The second cut will cost 13, and should be used to cut the 13 into 8 and 5. This would cost 21+13=34. If the 21 was cut into 16 and 5 instead, the second cut would cost 16 for a total of 37 (which is more than 34).
Source
 
USACO 2006 November Gold

PS:复制无法保留原格式,没感觉啊

翻译见书p47


合并果子一类型的题。

朴素的贪心法O(n^2)

贪心策略:每次选择长度最小和次小的两个木板进行合并,将这两个木板长度之和加入ans中,知道木板数为1

思路来源:可以用二叉树来描述,其实是一棵哈夫曼树。

可以推导出

ans=sigma(L[i]*h[i]) h[i]为节点的深度

于是最佳切割方法应当满足: 最短板与次短板为兄弟节点,且为当前深度最大

每次找到最小值与次小值,递归求解即可(递归是一种思想,不一定要写成递归函数的形式)

 

由于每次都要找到最小值与次小值,可用优先队列实现。不仅能达到O(nlogn),而且理解容易又易于编写~!

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<string>
#define inf 1000000000
#define maxn 300000
#define maxm 500+100
#define eps 1e-10
#define ll long long
#define pa pair<int,int>
#define for0(i,n) for(int i=0;i<=(n);i++)
#define for1(i,n) for(int i=1;i<=(n);i++)
#define for2(i,x,y) for(int i=(x);i<=(y);i++)
#define for3(i,x,y) for(int i=(x);i>=(y);i--)
#define mod 1000000007
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') {x=10*x+ch-'0';ch=getchar();}
	return x*f;
}
const int M=20000+10; 
int n,L[M];
ll int ans;
priority_queue<int,vector<int>,greater<int> > q;
void solve()
{
	ll ans=0;
	while(q.size()>1)
	{
		int min1=q.top();q.pop();
		int min2=q.top();q.pop();
		int t=min1+min2;
		ans+=t;
		q.push(min1+min2); 
	}
	printf("%lld\n",ans);
	return ;
}
int main()
{
	n=read();
	for1(i,n) L[i]=read();
	for1(i,n) q.push(L[i]);
	/*可以直接写作 
	for1(i,n) q.push(L[i]);
	*/ 
	ans=0;
	solve();
	return 0;
} 

给了俺信心!继续努力~

Category: 优先队列 | Tags: | Read Count: 621

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com