贪心水题题解
这里是三道贪心的水题。
营养膳食
题目描述
阿月正在女朋友宁宁的监督下完成自己的增肥计划。
为了增肥,阿月希望吃到更多的脂肪。然而也不能只吃高脂肪食品,那样的话就会导致缺少其他营养。阿月通过研究发现:真正的营养膳食规定某类食品不宜一次性吃超过若干份。
比如就一顿饭来说,肉类不宜吃超过 1 份,鱼类不宜吃超过 1 份,蛋类不宜吃超过 1 份,蔬菜类不宜吃超过 2 份。阿月想要在营养膳食的情况下吃到更多的脂肪,当然阿月的食量也是有限的。
输入
输入第一行包含三个正整数 n(n≤200),m(m≤100)和k(k≤100)。表示阿月每顿饭最多可以吃 m 份食品,同时有 n 种食品供阿月选择,而这 n 种食品分为 k 类。
第二行包含 k 个不超过 10 的正整数,表示可以吃 1 到 k 类食品的最大份数。接下来 n 行每行包括 2 个正整数,分别表示该食品的脂肪指数 ai 和所属的类别 bi,其中 ai≤100,bi≤k。
输出
输出一个数字即阿月可以吃到的最大脂肪指数和。
样例输入
6 6 3
3 3 2
15 1
15 2
10 2
15 2
10 2
5 3
样例输出
60
解析:
贪心的题总会出现“更多”,“最多”等字眼(不过好像每道题都是这样)。在大概读完题之后,如果觉得能用贪心解决,那就想一个贪心。如果能举出反例,就再想一个贪心方法,如果最后反数据多得让你发现这道题不能再用贪心了,那正解可能是dp什么的。其实考试题不能轻易出贪心的,即使是贪心题也是得让你看不出来他是贪心,或者贪心的方法特别难。
本道题的最优解是:按脂肪排序。每次吃脂肪最多的食物,如果当前食物的种类已经吃到上限了,那就不吃这个食物。
代码:
#include<cstdio> #include<algorithm> using namespace std; int n,m,k; int lim[105]; int ans; struct food { int fat; int kk; }; bool cmp(food a,food b) { return a.fat > b.fat; } food num[205]; int main() { // freopen("diet.in","r",stdin); // freopen("diet.out","w",stdout); scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=k;i++) scanf("%d",&lim[i]); for(int i=1;i<=n;i++) scanf("%d%d",&num[i].fat,&num[i].kk); sort(num+1,num+n+1,cmp); for(int i=1;i<=m;i++) { if(lim[num[i].kk] > 0) { ans += num[i].fat; lim[num[i].kk] -= 1; } } printf("%d",ans); return 0; }
整数区间
题目描述
一个整数区间[A,B]
请编程完成以下任务:
1.从文件中读取区间的个数及其它们的描述;
2.找到满足下述条件的所含元素个数最少的集合中元素的个数,对于每一个区间,都至少
有两个不同的整数属于该集合。
输入
首行包括区间的数目 n,1<=n<=10000,接下来的 n 行,每行包括两个整数 a,b,被一空格隔开,0<=a<=b<=10000,它们是某一个区间的开始值和结束值。
输出
第一行集合元素的个数,对于每一个区间都至少有两个不同的整数属于该区间,且集合所包含元素数目最少。
输入
4
3 6
2 4
0 2
4 7
输出
4
解释一下:
可能题面描述的不太好,我解释一下。就是找一些最少的数,使每个区间至少包含这些数中的两个数,输出数的个数。
我的代码:
#include<cstdio> #include<algorithm> using namespace std; int cc[10005]; int ans,gg; bool cmp(int a,int b) { return a>b; } int main() { // freopen("a.in","r",stdin); // freopen("a.out","w",stdout); int l,r,n,mini=0x7fffffff,maxi=0; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d",&l,&r); for(int j=l;j<=r;j++) { cc[j]++; } mini = min(l,mini); maxi = max(r,maxi); } sort(cc+mini,cc+maxi,cmp); for(int i=mini;i<=maxi;i++) { ans += cc[i]; gg++; if(ans >= 2*n) break; } printf("%d",gg); return 0; } /* 4 3 6 2 4 0 2 4 7 */
解析:
要不怎么说这道题数据水。我的方法绝对有瑕疵。
我是这么干的。取1到10000这个区间(整形数组,1~10000是下标)。每读入一个区间,就把它覆盖上(就是这个数组每个下标存的数+1),这样把这些区间捏到一起,再将这个覆盖后的数组降序排序,然后从大到小一直累加加加,一直加到比区间个数n的二倍大,输出累加的这些数的个数。
这个方法太土了,我都不知道怎么证他是对的这道题就a了。所以一定是数据太水了。我给一个正解代码吧。
正解代码:
#include<iostream> #include<algorithm> using namespace std; struct node { int l; int r; }a[10001]; bool cmp(node a,node b) { return (a.r<b.r||a.r==b.r&&a.l<b.l); } int main() { int n;cin>>n; for(int i=1;i<=n;i++) cin>>a[i].l>>a[i].r; sort(a+1,a+n+1,cmp); int q[10001],front=2,back=1; q[1]=a[1].r-1;q[2]=a[1].r; for(int i=2;i<=n;i++) { int k=back; while(a[i].l>q[back]&&back<k+2) back++; if(back==k+1) q[++front]=a[i].r; if(back==k+2) q[++front]=a[i].r-1,q[++front]=a[i].r; } cout<<front; } #include <stdio.h> #define maxN 10005//最大边条数 #define inf 0x7fffffff//最大距离 struct Edge { int v, w, next; }edge[4 * maxN];//边集 int dis[maxN]; bool vis[maxN]; int queue[maxN]; int preEdge[maxN];//同一个顶点的前一条边 int edgeNum,n,maxn; void addEdge(int u, int v, int w)//添加一条边 { edge[edgeNum].v = v; edge[edgeNum].w = w; edge[edgeNum].next = preEdge[u]; preEdge[u] = edgeNum ++; } void spfa()//spaf算法 { int head = 0, tail = 1; for (int i = 0; i <= maxn; ++ i) { dis[i] = -inf; } queue[head] = 0; dis[0] = 0; while (head != tail) { int u = queue[head]; vis[u] = true; for (int p = preEdge[u]; p != 0; p = edge[p].next) { int v = edge[p].v; if (dis[v] < dis[u] + edge[p].w) { dis[v] = dis[u] + edge[p].w; if (!vis[v]) { vis[v] = true; queue[tail] = v; tail ++; if (tail == maxN) { tail = 0; } } } } vis[u] = false; head ++; if (head == maxN) { head = 0; } } } int main() { scanf("%d", &n); edgeNum = 1; maxn = 0; while (n --) { int u, v; scanf("%d%d", &u, &v); if (v + 1 > maxn) { maxn = v + 1; } addEdge(u, v + 1, 2); } for (int i = 0; i <= maxn; ++ i) { addEdge(i, i + 1, 0); addEdge(i + 1, i, -1); } spfa(); printf("%d\n", dis[maxn]); return 0;
运输
题目描述
现在已知 N 件商品,和搬运它们其中每一件的费用。现在搬家公司老板 Mr.sb 决定让我们每次任意选取 2 件商品。然后这 2 件商品只算一件商品的费用。但是这个商品的搬运费用是将选出的 2 个商品的费用之和除以 k 的运算结果。如此反复。直到只收一件商品的钱。这个就是商店要付的费用。掌柜的想尽可能的少付钱,以便将更多的钱捐给希望工程。所以请你帮他计算一下最少只用付多少钱。
输入
n,k
w1,w2,...,wn(每一件商品的搬运费用)
n,k<=10000
输出
最少付多少钱
样例输入
5 2
1 2 3 4 5
样例输出
1
解析:
贪心策略就是取两个最大的数,除完k放回去,再取两个最大的,再放回去……因为贪心总是什么取最大啦,排序啦这个样子。用优先队列就比较方便。
代码:
#include<cstdio> #include<algorithm> #include<queue> typedef long long ll; using namespace std; int n,k,hop; priority_queue <int> q; int main() { // freopen("trans.in","r",stdin); // freopen("trans.out","w",stdout); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { scanf("%d",&hop); q.push(hop); } while(n>1) { hop = q.top(); q.pop(); hop += q.top(); q.pop(); hop /= k; q.push(hop); n--; } printf("%d",hop); return 0; }
posted on 2018-03-17 22:44 Ch_someone 阅读(420) 评论(0) 编辑 收藏 举报