8.贪心算法

[复制链接]
发表于 2025-10-14 08:24:02 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
简单贪心

1.P10452 货仓选址 - 洛谷


 

  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. typedef long long LL;
  5. const int N = 1e5+10;
  6. LL a[N];
  7. LL n;
  8. int main()
  9. {
  10.         cin>>n;
  11.         for(int i = 1;i <= n;i++)cin>>a[i];
  12.         sort(a+1,a+1+n);//排序
  13.         LL sum = 0;
  14.         //for(int i = 1;i <= n;i++)
  15.         //{
  16.         //        sum+=(abs(a[i]-a[(1+n)/2]));
  17.         //}
  18.        
  19.         for(int i = 1;i <= n/2;i++)
  20.         {
  21.                 sum += abs(a[i]-a[n+1-i]);
  22.         }
  23.         cout<<sum<<endl;
  24.         return 0;
  25. }
复制代码
2.P1115 最大子段和 - 洛谷




  1. #include<iostream>
  2. using namespace std;
  3. typedef long long LL;
  4. const int N = 2e5+10;
  5. LL a[N];
  6. LL n;
  7. int main()
  8. {
  9.         cin>>n;
  10.         for(int i = 1;i <= n;i++)cin>>a[i];
  11.        
  12.         LL sum = 0;LL ret = -1e5;
  13.         for(int i = 1;i <= n;i++)
  14.         {
  15.                 sum+=a[i];
  16.                 ret = max(sum,ret);
  17.                 if(sum < 0)sum = 0;
  18.          }
  19.          cout<<ret<<endl;
  20.          return 0;
  21. }
复制代码
  舍弃的想法很大胆,也很有风险,但通过证实,就可以表现通过
  3. P1094 [NOIP 2007 遍及组] 怀念品分组 - 洛谷



  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. int w,n;
  5. const int N = 3e4+10;
  6. int a[N];
  7. int main()
  8. {
  9.         cin>>w>>n;
  10.         for(int i = 1;i <= n;i++)cin>>a[i];
  11.         //排序
  12.          sort(a+1,a+1+n);
  13.          int l = 1,r = n,ret = 0;
  14.          while(l <= r)
  15.          {
  16.                  //最小和最大相加小于w,符合 ,同时异位
  17.                  if(a[l]+a[r]<=w)l++,r--;
  18.                  //l待定。r--
  19.                  else
  20.                  {
  21.                          r--;
  22.                  }
  23.                  ret++;
  24.          }
  25.          cout<<ret<<endl;
  26.          return 0;
  27.        
  28. }
复制代码
 4.P1056 [NOIP 2008 遍及组] 排座椅 - 洛谷



  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. int m, n, k, l, d;
  5. const int N = 1010;
  6. struct  node
  7. {
  8.         int index;//存行列的下标
  9.         int cnt;//存取该行或者该列能隔开多少对同学
  10. }row[N],col[N];
  11. //按照cnt从大到小排列
  12. bool cmp1(node& x, node& y)
  13. {
  14.         return x.cnt > y.cnt;
  15. }
  16. //按照下标从小到大排列
  17. bool cmp2(node& x, node& y)
  18. {
  19.         return x.index < y.index;
  20. }
  21. int main()
  22. {
  23.         cin >> m >> n >> k >> l >> d;
  24.         //初始化数组,赋值index
  25.         for (int i = 1; i <= m; i++)row[i].index = i;
  26.         for (int i = 1; i <= n; i++)col[i].index = i;
  27.         //计算cnt
  28.         while (d--)
  29.         {
  30.                 int x, y, p, q; cin >> x >> y >> p >> q;
  31.                 if (x == p)col[min(y, q)].cnt++;
  32.                 else
  33.                         row[min(x, p)].cnt++;
  34.         }
  35.         //通过cnt把大的排在前面-->cmp1
  36.         sort(row + 1, row + 1 + m, cmp1);
  37.         sort(col + 1, col + 1 + n, cmp1);
  38.         //把前k或者l大的按照下表从小到大进行排列
  39.         sort(row + 1, row + 1 + k, cmp2);
  40.         sort(col + 1, col + 1 + l, cmp2);
  41.         //输出
  42.         //行
  43.         for (int i = 1; i <= k; i++)
  44.         {
  45.                 cout << row[i].index << " ";
  46.         }
  47.         cout << endl;
  48.         //列
  49.         for (int i = 1; i <= l; i++)
  50.         {
  51.                 cout << col[i].index << " ";
  52.         }
  53.         return 0;
  54. }
复制代码
  1.把每一行和每一列可以隔开的同砚纪录到cnt中
  2.按照cnt从大到小举行分列
  3.按照index对前k大概l个举行从小到大的分列
  4.输出前k 或 l的index下标
  4.矩阵消除游戏 


 




  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstring>
  4. using namespace std;
  5. int calc(int x)
  6. {
  7.         int ret = 0;
  8.         while (x)
  9.         {
  10.                 x = x & (x - 1);
  11.                 ret++;
  12.         }
  13.         return ret;
  14. }
  15. bool cmp(int x, int y)
  16. {
  17.         return x > y;
  18. }
  19. int n, m,k;
  20. const int N = 100;
  21. int a[N][N];
  22. int col[N];
  23. int main()
  24. {
  25.         cin >> n >> m >> k;
  26.         for (int i = 0; i < n; i++)
  27.         {
  28.                 for (int j = 0; j < m; j++)
  29.                 {
  30.                         cin >> a[i][j];
  31.                 }
  32.         }
  33.         int sum = 0, ret = 0;
  34.         //暴力枚举所有的第一行
  35.         for (int st = 0; st < (1 << n); st++)
  36.         {
  37.                 sum = 0;
  38.                 int num_1 = calc(st);
  39.                 //超过就不要了
  40.                 if (num_1 > k)continue;
  41.                 memset(col, 0, sizeof(col));
  42.                 for (int i = 0; i < n; i++)
  43.                 {
  44.                         //加上当前行的数字
  45.                         for (int j = 0; j < m; j++)
  46.                         {
  47.                                 if (((st >> i) & 1) == 1)
  48.                                 {
  49.                                         sum += a[i][j];
  50.                                 }
  51.                                 else
  52.                                 {
  53.                                         col[j] += a[i][j];
  54.                                 }
  55.                         }
  56.                 }
  57.                 //对列进行从大到小排序,取前k - num_1个
  58.                 int remain = k - num_1;
  59.                 sort(col, col + m, cmp);
  60.                 for (int i = 0; i < remain; i++)sum += col[i];
  61.                 ret = max(ret, sum);
  62.         }
  63.         cout << ret << endl;
  64.         return 0;
  65. }
复制代码
  暴力摆列行的全部选择方法,然后设置col,纪录行选择后,列的数据,remain表现剩余的操纵次数,对摆列行排序,取最大的前remain个即可。, 
  推公式

   1.在确定好的序次序列中,拿出相邻的两个元素
2.互换这两个元素,对前面和反面确定好序次的序列的结果不造成影响
3.根据这两个原色互换前后的结果推导出排序的规
  


1.P1012 [NOIP 1998 进步组] 拼数 - 洛谷



  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. int n;
  5. const int N = 25;
  6. string st[N];
  7. bool cmp(string& x, string& y)
  8. {
  9.         return x + y > y + x;
  10. }
  11. int main()
  12. {
  13.         cin >> n;
  14.         for (int i = 0; i < n; i++)
  15.                 cin >> st[i];
  16.         sort(st, st+n, cmp);
  17.         for (int i = 0; i < n; i++)
  18.                 cout << st[i];
  19.         return 0;
  20. }
复制代码
   比力方法:两两元素相拼,
  2.P2878 [USACO07JAN] Protecting the Flowers S - 洛谷




   很震惊!! 
     1.在确定好的序次序列中,拿出相邻的两个元素
2.互换这两个元素,对前面和反面确定好序次的序列的结果不造成影响
3.根据这两个原色互换前后的结果推导出排序的
   
  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. typedef long long LL;
  5. LL n;
  6. const int N = 1e5+10;
  7. struct node
  8. {
  9.         LL t;//时间
  10.         LL d;//吃草速度
  11. }a[N];
  12. bool cmp(node& x,node&y)
  13. {
  14.         return x.t*y.d < x.d*y.t;
  15. }
  16. int main()
  17. {
  18.         cin>>n;
  19.         for(int i = 1;i <= n;i++)
  20.         {
  21.                 cin>>a[i].t>>a[i].d;
  22.         }
  23.         sort(a+1,a+n+1,cmp);
  24.         LL ret = 0,t = 0;
  25.         for(int i = 1;i <= n;i++)
  26.         {
  27.                 ret += a[i].d*t;
  28.                 t += 2*a[i].t;
  29.         }
  30.         cout<<ret<<endl;
  31. }
复制代码
3. P1842 [USACO05NOV] 奶牛玩杂技 - 洛谷



  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. typedef long long LL;
  5. const int N = 5e4+10;
  6. int n;
  7. struct node
  8. {
  9.         LL w;
  10.         LL s;       
  11. }a[N];
  12. //推公式得到,把max中较小的放在前面,会让总体压力值变得较小
  13. bool cmp(node&x,node&y)
  14. {
  15.         return max(-x.s,x.w-y.s) < max(-y.s,y.w-x.s);
  16. }
  17. int main()
  18. {
  19.         cin>>n;
  20.         for(int i = 1;i <= n;i++)
  21.         {
  22.                 cin>>a[i].w>>a[i].s;
  23.         }
  24.         sort(a+1,a+1+n,cmp);
  25.        
  26.         LL w = 0;
  27.         LL ret = -1e5;
  28.         for(int i = 1;i <= n;i++)
  29.         {
  30.                 ret = max(ret,w - a[i].s);
  31.                 w+=a[i].w;
  32.         }
  33.         cout<<ret<<endl;
  34.         return 0;
  35.        
  36. }
复制代码
  

  哈夫曼树 



1.P1090 [NOIP 2004 进步组] 归并果子 - 洛谷 


  1. #include<iostream>
  2. #include<queue>
  3. #include<vector>
  4. using namespace std;
  5. typedef long long LL;
  6. priority_queue<LL,vector<LL>,greater<LL>>heap;
  7. LL n;
  8. int main()
  9. {
  10.         cin>>n;
  11.         for(int i = 1;i <= n;i++)
  12.         {
  13.                 LL x;cin>>x;
  14.                 heap.push(x);
  15.         }
  16.         LL sum = 0;
  17.         while(heap.size()>1)
  18.         {
  19.                 LL x = heap.top();heap.pop();
  20.                 LL y = heap.top();heap.pop();
  21.                 sum+=(x+y);
  22.                 heap.push(x+y);
  23.          }
  24.          cout<<sum<<endl;
  25. }
复制代码
 区间标题

   这种题⽬的办理⽅式⼀般就是按照区间的左端点大概是右端点排序,然后在排序之后的区间上,根据 题⽬要求,订定出相应的贪⼼计谋,进⽽得到最优解。
  
  具体是根据左端点还是右端点排序?升序还是降序?⼀般是假设⼀种排序⽅式,而且订定贪⼼计谋, 当没有显着的反例时,就可以实验去写代码。
  1.P1803 缭乱的yyy / 线段覆盖 - 洛谷


  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. const int N = 1e6+10;
  5. int n;
  6. struct node
  7. {
  8.         int s;
  9.         int e;
  10. }a[N];
  11. bool cmp(node&x,node&y)
  12. {
  13.         return x.s < y.s;
  14. }
  15. int main()
  16. {
  17.         cin>>n;
  18.         for(int i = 1;i <= n;i++)
  19.         {
  20.                 cin>>a[i].s;
  21.                 cin>>a[i].e;
  22.         }
  23.        
  24.         sort(a+1,a+1+n,cmp);//按照起点开始由小到大的顺序排列
  25.         int ret = 1;
  26.         int r = a[1].e;
  27.         for(int i = 2;i <= n;i++)
  28.         {
  29.                 int right = a[i].e,left = a[i].s;
  30.                 if(left < r)//重叠了,不能参加,如果重叠的右端比前面那一个还小,那就贪,覆盖前面哪一个
  31.                 {
  32.                         r = min(r,right);
  33.                 }
  34.                 else
  35.                 {
  36.                         ret++;//没有重叠,可以参加
  37.                         r = right;//更新较小的r
  38.                  }
  39.         }
  40.         cout<<ret<<endl;
  41.         return 0;
  42.          
  43. }
复制代码

 

2.UVA1193 Radar Installation - 洛谷



   按照左端点排序,相互重叠的区间是连续的 
    二维标题转化成一维标题 
    证实: 按照左端点排序,相互重叠的区间是连续的 
  

  1. #include<iostream>
  2. #include<cmath>
  3. #include<algorithm>
  4. using namespace std;
  5. const int N = 1e3+10;
  6. int n,d;
  7. struct node
  8. {
  9.         double l;
  10.         double r;
  11. }a[N];
  12. bool cmp(node&x,node&y)
  13. {
  14.         return x.l < y.l;
  15. }
  16. int main()
  17. {
  18.         int cnt = 1;
  19.         while(cin>>n>>d&&(n&&d))
  20.         {
  21.                 int flag = 1;
  22.                 for(int i = 1;i <= n;i++)
  23.                 {
  24.                         int x,y;cin>>x>>y;
  25.                         if(y > d)flag = -1;
  26.                         //把二维映射到一维上去
  27.                         double l =  sqrt(d*d - y*y);
  28.                         a[i].l = x - l;
  29.                         a[i].r = x + l;
  30.                 }
  31.                 sort(a+1,a+1+n,cmp);
  32.         int ret = 1;
  33.         int r = a[1].r;
  34.         cout<<"Case "<<cnt<<": ";
  35.         cnt++;
  36.         for(int i = 2;i <= n;i++)
  37.         {
  38.                 int left = a[i].l,right = a[i].r;
  39.                 if(left<=r)//等于也可以扫到
  40.                 {
  41.                         //扫描通过
  42.                         r =  min(r,right);
  43.                 }else
  44.                 {
  45.                         ret++;
  46.                         r = right;
  47.                 }
  48.         }
  49.        
  50.         cout<<ret<<endl;
  51. }
  52.         return 0;
  53. }
复制代码

3.P2887 [USACO07NOV] Sunscreen G - 洛谷

 



  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. const int N = 3e3+10;
  5. int n,l;
  6. struct node
  7. {
  8.         int l;//表示奶牛耐受的最小值//防晒霜的防晒值
  9.         int r;//奶牛耐受的最大值// 防晒霜的数量
  10. }a[N],b[N];
  11. bool cmp(node&x,node&y)
  12. {
  13.         return x.l > y.l;
  14. }
  15. int main()
  16. {
  17.         cin>>n>>l;
  18.         for(int i = 1;i <= n;i++)
  19.         {
  20.                 cin>>a[i].l>>a[i].r;//输入奶牛耐受值
  21.         }
  22.         for(int i = 1;i <= l;i++)
  23.         {
  24.                 cin>>b[i].l>>b[i].r;//输入防晒霜的防晒值和数量
  25.         }
  26.         //按照奶牛奶牛左端从大到小进行排序
  27.         sort(a+1,a+1+n,cmp);
  28.         //按照防晒霜防晒值从大到小进行排序
  29.         sort(b+1,b+1+l,cmp);
  30.         int ret = 0;
  31.         for(int i = 1;i <= n;i++)
  32.         {
  33.                 //选择一种防晒霜
  34.                 for(int j = 1;j <= l;j++)       
  35.                 {
  36.                         if(b[j].r == 0)continue;
  37.                         if(b[j].l<=a[i].r&&b[j].l>=a[i].l)
  38.                         {
  39.                                 //符合条件,ret++,数量--
  40.                                 ret++;
  41.                                 b[j].r--;
  42.                                 break;//选完一个就直接除去,免得后面的都没了
  43.                         }
  44.                 }
  45.         }
  46.         cout<<ret<<endl;
  47.         return 0;
  48. }
复制代码

 4.P2859 [USACO06FEB] Stall Reservations S - 洛谷


  1. #include<iostream>
  2. #include<queue>
  3. #include<algorithm>
  4. using namespace std;
  5. const int N = 5e4 + 10;
  6. int n;
  7. struct node
  8. {
  9.         int l;//牛牛的开始//该牛棚的结束时间
  10.         int r;//牛牛的结束 //该牛棚的编号
  11.         int num;//这只牛的编号
  12.         bool operator<(const node& y)const
  13.         {
  14.                 return l > y.l;//创建小根堆
  15.         }
  16. }a[N];
  17. bool cmp(node& x, node& y)
  18. {
  19.         return x.l < y.l;
  20. }
  21. int res[N];//记录每只牛进入的牛棚顺序
  22. priority_queue<node> heap;//建议一个关于牛棚结束时间的小根堆,找出当前技术时间最早的,拉出来
  23. int main()
  24. {
  25.         cin >> n;
  26.         for (int i = 1; i <= n; i++)
  27.         {
  28.                 cin >> a[i].l >> a[i].r;
  29.                 a[i].num = i;
  30.         }
  31.         //按照左端点从小到大排列
  32.         sort(a + 1, a + 1 + n, cmp);
  33.         int ret = 1;//记录牛棚状态
  34.         heap.push({ a[1].r,1 });
  35.         res[a[1].num] = 1; //一号牛进一号棚
  36.         for (int i = 2; i <= n; i++)
  37.         {
  38.                 int l = a[i].l, r = a[i].r;
  39.                 int ete = heap.top().l;
  40.                 int num_peng = heap.top().r;
  41.                 if (ete >= l)//如果最短结束时间都>这只牛的开始的起始时间,那么就必须新开一个牛棚
  42.                 {
  43.                         ret++;
  44.                         heap.push({ r,ret });
  45.                         res[a[i].num] = ret;
  46.                 }
  47.                 else//可以拿下
  48.                 {
  49.                         heap.pop();//结束不要了
  50.                         heap.push({ r,num_peng });//把这只牛推入彭中
  51.                         res[a[i].num] = num_peng;
  52.                 }
  53.         }
  54.         cout << ret << endl;
  55.         for (int i = 1; i <= n; i++)cout << res[i] << endl;
  56. }
复制代码



回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表