哈夫曼树(POJ3253)
来源:互联网 发布:深圳市逻辑思维软件 编辑:程序博客网 时间:2024/06/03 20:13
题目
POJ3253
大概题意:XX想修补东西,然后需要用木板。可以认为XX有一根无限长(长度=他需要的木板长度总和)的木板,但是他需要N块长度为Li的木板,所以他需要把这块无限长的木板锯成他需要的。每次锯木板的花费与锯之前木板的长度相等。求最小花费!
测试案例:
3
8
5
8
34
sum=0;
开始木板长度21(8+5+8),sum+=21,要锯成13+8;
然后,需要锯的木板长度13,sum+=13,要锯成5+8;
所以sum=34.
(写代码时可以将过程反过来。)
如何确定每次锯的木板的长度,用到的就是“哈夫曼树”的思想。每次取最优,又符合贪心的思想。
但是仅仅是这样,会超时的。
第一步
我用的数组存的所有的数,每次都排序完,取前两个数的和。
毫无疑问超时。O(n^2logn)
TLE
第二步
我将数组改成链表,使用插入排序,以为可以优化.
但是,还是超时。O(n^2)
代码(TLE)
#include<iostream>#include<cstring>#include<string>#include<cstdio>#include<cmath>#include<algorithm>#include <set>#include <map>#include<list>#include <stack>#include <queue>#include <vector>#include <ctime>#define ll long long#define f(i,a,b) for(int i=a;i<=b;i++)#define m(a,b) memset(a,b,sizeof(a))#define MAX 0x3f3f3f3fconst ll MOD=1e+9+7;using namespace std;struct Node{ ll data; Node* next;};typedef Node* linklist;linklist head;void assert(ll n){ linklist p=head; linklist q=new(Node); if(p->next==NULL){ q->data=n; q->next=NULL; p->next=q; } else if(n<=p->next->data){ q->data=n; q->next=p->next; p->next=q; } else { p=p->next; bool flag=1; while(p->next!=NULL){ if(n<=p->next->data){ q->data=n; q->next=p->next; p->next=q; flag=0; break; } p=p->next; } if(flag){ q->data=n; q->next=NULL; p->next=q; } }}void del(linklist p){ linklist q=p->next; p->next=q->next; delete(q);}ll operate(){ ll temp=head->next->data+head->next->next->data; del(head); del(head); assert(temp); return temp;}int main(){ head=new(Node); head->next=NULL; int n; cin>>n; f(i,0,n-1){ ll a; cin>>a; assert(a); } ll ans=0; f(i,0,n-2){ ans+=operate(); } cout<<ans<<endl; return 0;}
第三步
我以为我以为就是我以为的。。。
看了别人的代码,才知道,问题处在了别的地方,但是说实话,我感觉只是测试数据不够强,不然代码同样会被卡死。为什么这么说呢,请看我改过之后的AC代码。目前对标程了解尚浅。。。
AC代码
#include<iostream>#include<cstring>#include<string>#include<cstdio>#include<cmath>#include<algorithm>#include <set>#include <map>#include<list>#include <stack>#include <queue>#include <vector>#include <ctime>#define ll long long#define f(i,a,b) for(int i=a;i<=b;i++)#define m(a,b) memset(a,b,sizeof(a))#define MAX 0x3f3f3f3fconst ll MOD=1e+9+7;using namespace std;struct Node{ ll data; Node* next;};typedef Node* linklist;linklist head;void assert(ll n){ linklist p=head; linklist q=new(Node); if(p->next==NULL){ q->data=n; q->next=NULL; p->next=q; } else if(n<=p->next->data){ q->data=n; q->next=p->next; p->next=q; } else { p=p->next; bool flag=1; while(p->next!=NULL){ if(n<=p->next->data){ q->data=n; q->next=p->next; p->next=q; flag=0; break; } p=p->next; } if(flag){ q->data=n; q->next=NULL; p->next=q; } }}void del(linklist p){ linklist q=p->next; p->next=q->next; delete(q);}ll operate(){ ll temp=head->next->data+head->next->next->data; del(head); del(head); assert(temp); return temp;}int main(){ head=new(Node); head->next=NULL; int n; scanf("%d",&n); int s[20020]; f(i,0,n-1){ scanf("%d",&s[i]); } sort(s,s+n); linklist p=head; f(i,0,n-1){ linklist q=new(Node); q->data=s[i]; q->next=NULL; p->next=q; p=q; } ll ans=0; f(i,0,n-2){ ans+=operate(); } cout<<ans<<endl; return 0;}
看出来我该那里了么?
就是开始读入数据构造链表的时候。
代码TLE,直接就是输入一个插入一个,时间复杂度最坏是O((N^2)/2),AC代码,将这个构造链表的过程优化到了O(N*logN);
至于,主要的算法实现的过程,倒是没卡O((N^2)/2).
不清楚呀,为什么?
可能是,两个时间复杂度O(输入+插入)
第四步
学习别人代码:
优先队列的构造使用
《待补充》STL中优先队列的使用
《待补充》
STL代码
/*STL 优先队列*///Memory Time//512K 47MS#include<iostream>#include<vector>#include<queue>#include<cstdio>using namespace std;//比较规则,最小优先class cmp{public: bool operator()(const __int64 a,const __int64 b)const { return a>b; }};int main(void){ int n; //需要切割的木板个数 while(cin>>n) { priority_queue<__int64,vector<__int64>,cmp>Queue; //定义优先队列 for(int i=1;i<=n;i++) { __int64 temp; scanf("%I64d",&temp); Queue.push(temp); //输入要求的木板长度(费用)并入队 } __int64 mincost=0; //最小费用 while(Queue.size()>1) //当队列中小于等于一个元素时跳出 { __int64 a=Queue.top(); //得到队首元素的值,并使其出队 Queue.pop(); __int64 b=Queue.top(); //两次取队首,即得到最小的两个值 Queue.pop(); Queue.push(a+b); //入队 mincost+=a+b; } printf("%I64d\n",mincost); while(!Queue.empty()) //清空队列 Queue.pop(); } return 0;}
Finally
个人感觉,利用堆,才是AC这道题的最好办法。上述AC代码,过的并不能说服人,凑巧罢了。
利用堆,能将哈夫曼算法实现部分的时间复杂度优化到O(nlogn).
学习,如何构造堆,利用堆来实现哈夫曼树。
#include <iostream>using namespace std;long long n,i,ans,p[20001];void heap(long x,long y){ long i,j,temp; temp=p[x]; i=x; j=i*2; while(j<=y) { if(j<y&&p[j+1]<p[j]) j++; if(temp>p[j]) { p[i]=p[j]; i=j; j=i*2; } else break; } p[i]=temp;}int main(){ cin>>n; ans=0; for(i=1;i<=n;i++) cin>>p[i]; for(i=n/2;i>=1;i--) heap(i,n); while(n>1) { p[0]=p[1]; p[1]=p[n--]; heap(1,n); p[1]+=p[0]; ans+=p[1]; heap(1,n); } cout<<ans<<endl; return 0;}
- 哈夫曼树(POJ3253)
- 优先级队列(哈夫曼树)poj3253
- poj3253(优先队列 哈夫曼树)
- POJ3253--哈夫曼树
- poj3253,哈夫曼树
- POJ3253 Fence Repair(贪心,哈夫曼树)
- POJ3253(STL)
- poj3253(贪心)
- poj3253
- POJ3253
- poj3253
- poj3253
- poj3253
- poj3253
- POJ3253
- poj3253
- POJ3253
- poj3253
- NYOJ---1241 - Distribution
- Oracle-25-having子句&连接的定义(如多表联查)
- 1013
- Redis内存使用优化与存储
- 希尔排序
- 哈夫曼树(POJ3253)
- 1.2.4 Linux的开发:虚拟团队的产生
- leetcode - Contains Duplicate
- [C语言][LeetCode][142]Linked List Cycle II
- Win7免安装Mysql 5.6.24版本
- 位操作运算符
- web结构
- 零零碎碎(摘抄)
- UISearchBar 去掉灰色边框