https://www.luogu.org/problem/show?pid=1056

题目描述

上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情。不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的D对同学上课时会交头接耳。同学们在教室中坐成了M行N列,坐在第i行第j列的同学的位置是(i,j),为了方便同学们进出,在教室中设置了K条横向的通道,L条纵向的通道。于是,聪明的小雪想到了一个办法,或许可以减少上课时学生交头接耳的问题:她打算重新摆放桌椅,改变同学们桌椅间通道的位置,因为如果一条通道隔开了两个会交头接耳的同学,那么他们就不会交头接耳了。

请你帮忙给小雪编写一个程序,给出最好的通道划分方案。在该方案下,上课时交头接耳的学生的对数最少。

输入输出格式

输入格式:

输入的第一行,有5个用空格隔开的整数,分别是M,N,K,L,D(2<=N,M<=1000,0<=K<M,0<=L<N,D<=2000)。

接下来的D行,每行有4个用空格隔开的整数。第i行的4个整数Xi,Yi,Pi,Qi,表示坐在位置(Xi,Yi)与(Pi,Qi)的两个同学会交头接耳(输入保证他们前后相邻或者左右相邻)。

输入数据保证最优方案的唯一性。

输出格式:

输出共两行。

第一行包含K个整数,a1,a2……aK,表示第a1行和a1+1行之间、第a2行和a2+1行之间、…、第aK行和第aK+1行之间要开辟通道,其中ai< ai+1,每两个整数之间用空格隔开(行尾没有空格)。

第二行包含L个整数,b1,b2……bL,表示第b1列和b1+1列之间、第b2列和b2+1列之间、…、第bL列和第bL+1列之间要开辟通道,其中bi< bi+1,每两个整数之间用空格隔开(列尾没有空格)。

输入输出样例

输入样例#1:

  1. 4 5 1 2 3
  2. 4 2 4 3
  3. 2 3 3 3
  4. 2 5 2 4
输出样例#1:

  1. 2
  2. 2 4

说明

上图中用符号*、※、+标出了3对会交头接耳的学生的位置,图中3条粗线的位置表示通道,图示的通道划分方案是唯一的最佳方案。

题目中有一行“输入保证最优解唯一”

因此考虑贪心法:选择交头接耳人数最多的过道

程序实时处理交头接耳的人,判断他们“横跨”第几行/第几列,给相应的行/列交头接耳人数+1

然后选出人最多的行列(可以放心这么做否则解就是不唯一的矛盾),排序后输出即可

  1. 1 # include <stdio.h>
  2. 2 # define min(x,y) (x<y?x:y)
  3. 3 int main()
  4. 4 {
  5. 5 short M,N,row[999]={0},column[999]={0}, //教室里的座位共有M行N列(2≤M,N≤1000)
  6. 6 K,L,D,i,X[2000],Y[2000],P[2000],Q[2000]; //需要开辟K条横向通道和L条纵向通道
  7. 7 scanf("%hd %hd %hd %hd %hd",&M,&N,&K,&L,&D); //用以最大限度地隔离D对相邻的爱说话的同学
  8. 8 void passageway(short[],short,short); //函数passageway用于给出开辟通道的最优方案
  9. 9 for(i=0;i<D;i++) //每对相邻的爱说话的两个同学
  10. 10 scanf("%hi%hi%hi%hi",&X[i],&Y[i],&P[i],&Q[i]); //分别位于第X行第Y列和第P行第Q列
  11. 11 while(i--) //对于每对相邻的爱说话的两个同学
  12. 12 if(X[i]==P[i]) //当他们位于同一行的相邻列时
  13. 13 column[min(Y[i],Q[i])-1]++; //可以考虑在他们中间开辟一条纵向通道
  14. 14 else //当他们位于同一列的相邻行时
  15. 15 row[min(X[i],P[i])-1]++; //可以考虑在他们中间开辟一条横向通道
  16. 16 passageway(row,K,M); //输出需要开辟的K条横向通道的位置
  17. 17 passageway(column,L,N); //输出需要开辟的L条纵向通道的位置
  18. 18 return 0;
  19. 19 }
  20. 20 void passageway(short _[],short way,short all) //way为要求开辟的通道数,all为座位总行/列数
  21. 21 {
  22. 22 short t,passage=0,limit=0; //limit为开辟通道所需的爱说话同学的对数下限
  23. 23 while(passage!=way) //当下限limit设定不合适时
  24. 24 for(t=passage=0,limit++;t<all;t++) //增加下限limit,重新计算此时开辟的通道数
  25. 25 passage+=_[t]>=limit; //使其恰好等于要求开辟的通道数
  26. 26 for(t=0;way;t++) //当下限limit设定合适时
  27. 27 if(_[t]>=limit)
  28. 28 printf(--way?"%d ":"%d",t+1); //输出开辟的各条通道的位置
  29. 29 puts(""); //换行
  30. 30 }
  31. 31
  32. 32 //说明:0≤K<M,0≤L<N,D≤2000。对于输出的每个数a,表示在第a行/列和第(a+1)行/列之间开辟通道。

最普通最好用的蒟蒻方法。

使用结构体标记x,y轴,然后在读入每一对同学时,如果他们x轴相同就放在一个组,y轴相同放在另一个组,然后把对应的数组的值+1。

这样我们使用一个贪心的思路:对于x轴和y轴,某一条无论怎么分割对其他的分割线都没有影响。

因此,只需分别对读入后这两个结构体的值降序排序,取前k和前l个的位置坐标输出即可,可以证明这是最优的思路。

要注意有坑。在找出我们需要的位置时,别忘了对位置再排个序输出,不然WA声一片。

具体见代码吧,强迫症使然的c++选手。。。

快捷而简约的STL是个好东西。

  1. 1 #include<iostream>
  2. 2 #include<algorithm>
  3. 3 using namespace std;
  4. 4 struct seq{int i,val;}a[1010],b[1010];
  5. 5 int n,m,k,l,d,as[1010],bs[1010];
  6. 6 int x1,y1,x2,y2;
  7. 7 bool comp(seq,seq);
  8. 8 int main()
  9. 9 {
  10. 10 cin>>n>>m>>k>>l>>d;
  11. 11 for(int z=1;z<=1010;z++)
  12. 12 a[z].i=b[z].i=z;
  13. 13 for(int z=1;z<=d;z++)
  14. 14 {
  15. 15 cin>>x1>>y1>>x2>>y2;
  16. 16 if(x1==x2)
  17. 17 b[min(y1,y2)].val++;
  18. 18 if(y1==y2)
  19. 19 a[min(x1,x2)].val++;
  20. 20
  21. 21 }//对输入的数据处理,计算分割各个位置可以获得的值,min是为了取两个坐标的最小(反正差值是1)以方便累计
  22. 22
  23. 23 sort(a+1,a+1001,comp);
  24. 24 sort(b+1,b+1001,comp);
  25. 25 for(int z=1;z<=k;z++)
  26. 26 as[z]=a[z].i;
  27. 27 for(int z=1;z<=l;z++)
  28. 28 bs[z]=b[z].i;//对x,y轴的两个结构体的值排序并转移到记录位置的数组
  29. 29 sort(as+1,as+k+1);
  30. 30 sort(bs+1,bs+l+1);
  31. 31 for(int z=1;z<=k;z++)
  32. 32 cout<<as[z]<<" ";
  33. 33 cout<<endl;
  34. 34 for(int z=1;z<=l;z++)
  35. 35 cout<<bs[z]<<" ";
  36. 36 cout<<endl;//对两个记录位置的数组进行升序排序然后输出
  37. 37 return 0;
  38. 38 }
  39. 39 bool comp(seq i,seq j){return i.val>j.val;}

利用唯一答案的条件:

  1. #include<iostream>
  2. #include<string.h>
  3. #include<algorithm>
  4. using namespace std;
  5. int main()
  6. {
  7. int m,n,k,l,d;
  8. int s1[10001],s2[10001];
  9. fill(s1,s1+10001,0);
  10. fill(s2,s2+10001,0);
  11. cin>>m>>n>>k>>l>>d;
  12. int max1=0,max2=0;
  13. for (int i=1;i<=d;i++)
  14. {
  15. int a1,b1,c1,d1;
  16. cin>>a1>>b1>>c1>>d1;
  17. if (a1==c1)
  18. {
  19. if (b1<d1) s2[b1]++;
  20. else s2[d1]++;
  21. }
  22. else
  23. {
  24. if (a1<c1) s1[a1]++;
  25. else s1[c1]++;
  26. }
  27. }
  28. int a=0,b=0;
  29. for (int i=1;i<=10000;i++) if (s1[i]>=max1) max1=s1[i];
  30. for (int i=1;i<=10000;i++) if (s2[i]>=max2) max2=s2[i];
  31. while (a<k)
  32. {
  33. for (int i=1;i<=10000;i++) if (s1[i]==max1) a++;
  34. max1--;
  35. }
  36. max1++;
  37. while (b<l)
  38. {
  39. for (int i=1;i<=10000;i++) if (s2[i]==max2) b++;
  40. max2--;
  41. }
  42. max2++;
  43. for (int i=1;i<=10000;i++) if (s1[i]>=max1) cout<<i<<" ";
  44. cout<<endl;
  45. for (int i=1;i<=10000;i++) if (s2[i]>=max2) cout<<i<<" ";
  46. cout<<endl;
  47. return 0;
  48. }

洛谷P1056——排座椅(模拟,贪心,排序)的更多相关文章

  1. 洛谷 P1056 排座椅【贪心/结构体排序】

    题目描述 上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情.不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的D对同学上课时会交头接耳.同学 ...

  2. 洛谷P1056 排座椅

    洛谷P1056 排座椅 洛谷传送门 题目描述 上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情.不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有 ...

  3. 洛谷 P1056 排座椅 题解

    P1056 排座椅 题目描述 上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情.不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的 \(D\ ...

  4. 洛谷 P1056 排座椅

    P1056 排座椅 题目描述 上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情.不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的D对同学上 ...

  5. 洛谷 P1056 排座椅 桶排序

    桶排序大法好! 每次一看到这种范围小的题,本萌新就想用桶排. 因为题目中的m,n都小于1000,我们就可以定义两个1000的数组,表示每一行或每一列可以隔开几对讲话的童鞋. 然后再定义两个1000的数 ...

  6. 洛谷——P1056 排座椅

    https://www.luogu.org/problem/show?pid=1056#sub 题目描述 上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情.不过,班主 ...

  7. java实现 洛谷 P1056 排座椅

    import java.util.Arrays; import java.util.Map.Entry; import java.util.Scanner; import java.util.Tree ...

  8. 洛谷P1080(NOIP2012)国王游戏——贪心排序与高精度

    题目:https://www.luogu.org/problemnew/show/P1080 排序方法的确定,只需任取两个人,通过比较与推导,可以得出ai*bi小的人排在前面: 高精度写的时候犯了些细 ...

  9. [洛谷P3809]【模板】后缀排序

    [洛谷P3809][模板]后缀排序 题目大意: 对于给定的长度为\(n(n\le10^6)\)的字符串求后缀数组\(sa[i]\). 思路: 倍增+快排构造后缀数组.代码参考<挑战程序设计竞赛& ...

随机推荐

  1. Terracotta 2.7.2 Admin Console Guide

    http://www.terracotta.org/confluence/display/docs27/Admin+Console+Guide#AdminConsoleGuide-Roots

  2. 保存Total Commander的列宽

    Total Commander的默认列宽经常显示不全内容,需要手工调整,用"Menu -> Configuration -> Save Position"可以永久保存列 ...

  3. CSS Transform完全指南 #flight.Archives007

    Title/ CSS Transform完全指南 #flight.Archives007 序: 第7天了! 终身学习, 坚持创作, 为生活埋下微小的信仰. 我是忘我思考,共同进步! 简介: 一篇最简约 ...

  4. 【vue3】封装自定义全局插件

    [vue3]封装自定义全局插件 原vue2方法 main.js import Vue from 'vue' import App from './App.vue' import router from ...

  5. 006 PCI总线的桥与配置(一)

    在PCI体系结构中,含有两类桥片,一个是HOST主桥,另一个是PCI桥.在每一个PCI设备中(包括PCI桥)都含有一个配置空间.这个配置空间由HOST主桥管理,而PCI桥可以转发来自HOST主桥的配置 ...

  6. 使用Java8改造出来的模板方法真的是yyds

    GitHub 21.3k Star 的Java工程师成神之路,不来了解一下吗! GitHub 21.3k Star 的Java工程师成神之路,真的不来了解一下吗! 我们在日常开发中,经常会遇到类似的场 ...

  7. Flink项目实战(一)---核心概念及基本使用

    前言.flink介绍: Apache Flink 是一个分布式处理引擎,用于在无界和有界数据流上进行有状态的计算.通过对时间精确控制以及状态化控制,Flink能够运行在任何处理无界流的应用中,同时对有 ...

  8. SQL 练习40

    按照出生日期来计算学生的年龄信息 IF OBJECT_ID('GetStudentAge','FN') IS NOT NULL DROP FUNCTION GetStudentAge GO CREAT ...

  9. luogu P4206 聪聪和可可

    聪聪和可可 鸽了两天 \(dijkstra\)预处理出来两点之间的最短路径\(dis\)数组,读题发现,\(cat\)的走位很怪sb斩了,所以我们设一个\(next\)数组,\(next[i][j]\ ...

  10. NOIP 模拟 $19\; \rm u$

    题解 \(by\;zj\varphi\) 二维差分的题目 维护两个标记,一个向下传,一个向右下传: 对于每次更新,我们可以直接更新 \((r,c)+s,(r+l,c)-s\) ; \((r,c+1)- ...