180 likes | 300 Views
习题选讲. 贪心算法. 贪心算法. 1093 Air Express 1134 积木分发 1438 Shopaholic 1140 国王的 遗产 1090 Highways. 贪心算法. 1193 Up the Stairs 1004 I Conduit! 1017 Rate of Return 1059 Exocenter of a Trian 1003 Hit or Miss 1018 A Card Trick 1052 Candy Sharing Game 1041 Pushing Boxes 1211 商人的宣传
E N D
习题选讲 贪心算法
贪心算法 • 1093 Air Express • 1134 积木分发 • 1438 Shopaholic • 1140 国王的遗产 • 1090 Highways
贪心算法 • 1193 Up the Stairs • 1004 I Conduit! • 1017 Rate of Return • 1059 Exocenter of a Trian • 1003 Hit or Miss • 1018 A Card Trick • 1052 Candy Sharing Game • 1041 Pushing Boxes • 1211 商人的宣传 • 1071 Floors • 1082 MANAGER
1134 积木分发 • 题目大意: • 一个人手上有s块积木,一共有n个小朋友,每个小朋友手上有a块积木,还需要b块积木才能完成。当一个小朋友的积木完成后则全部回收利用。问是否所有小朋友都能完成。 • s<=1000000,n<=10000,a,b<=10^9
1134 积木分发 • 解题思路: • 尽量先满足需求少的小朋友,以回收得到更多积木; • 因此按小朋友的需求排序,贪心求解。
1134 积木分发 • 若两个小朋友分别已有和需求为a1,b1和a2,b2,且a1<a2,则先给第一个小朋友能完成的积木数s应该满足s>=a1 && s+b1>=a2,即s >= max(a1, a2-b1);先给第二个小朋友则s应该满足s>=a2 && s+b2>=a1,即s>=max(a2,a1-b2)>=a2。因为a2>max(a1,a2-b1),所以先给第二个小朋友的要求s更多,因此应先给第一个小朋友。
1134 积木分发 • struct child • { int a,b; }; • bool operator <(const child &x,cont child &y) • { return x.a<y.a; } • bool check(child children[],int s,int n) { • sort(children, children+n); • for (int i=0;i<n;i++) { • if (s<children[i].a) • return false; • s+=children[i].b; • } • return true; • }
1438 Shopaholic • 题目大意: • 买东西每买三件东西则最便宜的一件免费。给出n个需要买的东西的价格,问最多能免费多少? • n<=20000,价格不超过20000
1438 Shopaholic • 解题思路: • 尽量使价格高的东西免费; • 按价格从高到低排序后,每三件取一件免费; • sort(price,price+n); • for (i=n-3;i>=0;i-=3) • s+=price[i];
1140 国王的遗产 • n块金块组成一棵树,总共k个人,每个人选择树里的一条边去掉,得到不超过当前金块的一半的部分,并且分割使自己得到尽量多的金块,如果相等则使金块组编号最小。输出每个人得到的金块数量。 • n<=30000,k<=100
1140 国王的遗产 • 解题思路: • 枚举每个人的时候,检查切断每一条边所得到的金块数和组编号,并得到最大金块数和最小组编号。 • 切断每条边后,得到一棵子树,可计算得到子树节点数和最小编号; • 若每次从最小编号节点开始递归,则可以轻易比较子树的组编号以及它的补图的组编号。
1140 国王的遗产 • 每个人的答案,保存以下信息:得到的金块数,答案类型(是否包含根节点),最小编号(不包含根节点时)或缺少的最小编号(包含根节点时)去掉的边。 • struct ans { • enum anstype{withroot,withoutroot}; • int x,y,count,min; • anstype type; • };
1140 国王的遗产 • bool better(const ans &a,const ans &b) { • if (a.count!=b.count) • return a.count>b.count; • else if (a.type==ans::withroot) { • if (b.type==ans::withoutroot) • return true; • else • return a.min>b.min; • } else { • if (b.type==ans::withroot) • return false; • else • return a.min<b.min; • } • }
1140 国王的遗产 • vector<int> cal(int n,int k) { • int x=1,total=n,temp; • vector<int> ret; • for (;k>1;k--) { • best.count=-1; • x=predfs(x,-1); dfs(x,-1,temp); • erase(edge[best.x],best.y); • erase(edge[best.y],best.x); • if (best.type==ans::withroot) x=best.x; • total-=best.count; • ret.push_back(best.count); • } • ret.push_back(total); • return ret; • }
1140 国王的遗产 • int predfs(int cur,int parent) { • int min=cur; • for (int i=0;i<edge[cur].size();i++) { • if (edge[cur][i]==parent) • continue; • int temp=predfs(edge[cur][i],cur); • if (temp<min) • min=temp; • } • return min; • }
1140 国王的遗产 • int dfs(int cur,int parent,int &low) { • int subtree=1,templow=0; • low=cur; • for (int i=0;i<edge[cur].size();i++) { • if (edge[cur][i]==parent) • continue; • subtree+=dfs(edge[cur][i],cur,templow); • if (templow<low) • low=templow; • } • tempans.x=cur; • tempans.y=parent; • tempans.min=low; • // 以上找到当前节点与父节点的边的信息
1140 国王的遗产 • // 以下更新答案 • if (subtree<=total-subtree) { • tempans.count=subtree; • tempans.type=ans::withoutroot; • if (better(tempans,best)) • best=tempans; • } • if (total-subtree<=subtree&&subtree!=total) { • tempans.count=total-subtree; • tempans.type=ans::withroot; • if (better(tempans,best)) • best=tempans; • } • return subtree; • }