zoukankan      html  css  js  c++  java
  • 洛谷P1056——排座椅(模拟,贪心,排序)

    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:
    4 5 1 2 3
    4 2 4 3
    2 3 3 3
    2 5 2 4
    
    输出样例#1:
    2
    2 4
    

    说明

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

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

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

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

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

     1 # include <stdio.h>
     2 # define min(x,y) (x<y?x:y)
     3 int main()
     4 {
     5     short M,N,row[999]={0},column[999]={0},                //教室里的座位共有M行N列(2≤M,N≤1000)
     6         K,L,D,i,X[2000],Y[2000],P[2000],Q[2000];        //需要开辟K条横向通道和L条纵向通道
     7     scanf("%hd %hd %hd %hd %hd",&M,&N,&K,&L,&D);        //用以最大限度地隔离D对相邻的爱说话的同学
     8     void passageway(short[],short,short);                //函数passageway用于给出开辟通道的最优方案
     9     for(i=0;i<D;i++)                                    //每对相邻的爱说话的两个同学
    10         scanf("%hi%hi%hi%hi",&X[i],&Y[i],&P[i],&Q[i]);    //分别位于第X行第Y列和第P行第Q列
    11     while(i--)                                            //对于每对相邻的爱说话的两个同学
    12         if(X[i]==P[i])                                    //当他们位于同一行的相邻列时
    13             column[min(Y[i],Q[i])-1]++;                    //可以考虑在他们中间开辟一条纵向通道
    14         else                                            //当他们位于同一列的相邻行时
    15             row[min(X[i],P[i])-1]++;                    //可以考虑在他们中间开辟一条横向通道
    16     passageway(row,K,M);                                //输出需要开辟的K条横向通道的位置
    17     passageway(column,L,N);                                //输出需要开辟的L条纵向通道的位置
    18     return 0;
    19 }
    20 void passageway(short _[],short way,short all)            //way为要求开辟的通道数,all为座位总行/列数
    21 {
    22     short t,passage=0,limit=0;                            //limit为开辟通道所需的爱说话同学的对数下限
    23     while(passage!=way)                                    //当下限limit设定不合适时
    24         for(t=passage=0,limit++;t<all;t++)                //增加下限limit,重新计算此时开辟的通道数
    25             passage+=_[t]>=limit;                        //使其恰好等于要求开辟的通道数
    26     for(t=0;way;t++)                                    //当下限limit设定合适时
    27         if(_[t]>=limit)
    28             printf(--way?"%d ":"%d",t+1);                //输出开辟的各条通道的位置
    29     puts("");                                            //换行
    30 }
    31 
    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 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 struct seq{int i,val;}a[1010],b[1010];
     5 int n,m,k,l,d,as[1010],bs[1010];
     6 int x1,y1,x2,y2;
     7 bool comp(seq,seq);
     8 int main()
     9 {
    10     cin>>n>>m>>k>>l>>d;
    11     for(int z=1;z<=1010;z++)
    12         a[z].i=b[z].i=z;
    13     for(int z=1;z<=d;z++)
    14     {
    15         cin>>x1>>y1>>x2>>y2;
    16         if(x1==x2)
    17             b[min(y1,y2)].val++;
    18         if(y1==y2)
    19             a[min(x1,x2)].val++;
    20 
    21 }//对输入的数据处理,计算分割各个位置可以获得的值,min是为了取两个坐标的最小(反正差值是1)以方便累计
    22 
    23     sort(a+1,a+1001,comp);
    24     sort(b+1,b+1001,comp);
    25     for(int z=1;z<=k;z++)
    26         as[z]=a[z].i;
    27     for(int z=1;z<=l;z++)
    28         bs[z]=b[z].i;//对x,y轴的两个结构体的值排序并转移到记录位置的数组
    29     sort(as+1,as+k+1);
    30     sort(bs+1,bs+l+1);
    31     for(int z=1;z<=k;z++)
    32         cout<<as[z]<<" ";
    33     cout<<endl; 
    34     for(int z=1;z<=l;z++)
    35         cout<<bs[z]<<" ";
    36     cout<<endl;//对两个记录位置的数组进行升序排序然后输出
    37      return 0;
    38 }
    39 bool comp(seq i,seq j){return i.val>j.val;}

     利用唯一答案的条件:

    #include<iostream>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    int main()
    {
         int m,n,k,l,d;
         int s1[10001],s2[10001];
         fill(s1,s1+10001,0);
         fill(s2,s2+10001,0);
         cin>>m>>n>>k>>l>>d;
         int max1=0,max2=0;
         for (int i=1;i<=d;i++)
         {
             int a1,b1,c1,d1;
             cin>>a1>>b1>>c1>>d1;
             if (a1==c1)
             {
                    if (b1<d1) s2[b1]++;
                    else s2[d1]++;
            }
            else
            {
                 if (a1<c1) s1[a1]++;
                 else s1[c1]++;
            }
        }
        int a=0,b=0;
        for (int i=1;i<=10000;i++) if (s1[i]>=max1) max1=s1[i];
        for (int i=1;i<=10000;i++) if (s2[i]>=max2) max2=s2[i];
        while (a<k)
        {
            for (int i=1;i<=10000;i++) if (s1[i]==max1) a++;
            max1--;
        }
        max1++;
        while (b<l)
        {
            for (int i=1;i<=10000;i++) if (s2[i]==max2) b++;
            max2--;
        }
        max2++;
        for (int i=1;i<=10000;i++) if (s1[i]>=max1) cout<<i<<" ";
        cout<<endl;
        for (int i=1;i<=10000;i++) if (s2[i]>=max2) cout<<i<<" ";
        cout<<endl;
        return 0; 
    }
  • 相关阅读:
    javascript实现网页分享至朋友圈功能
    Vue中全局过滤器期与局部过滤器期的使用
    vue中添加与删除,关键字搜索
    vue生命周期
    4种常用的Ajax请求方式
    CSS 基础总结
    BEM思想之彻底弄清BEM语法
    学习前端过程中用到的资料
    深入理解,函数声明、函数表达式、匿名函数、立即执行函数、window.onload的区别.
    html基础
  • 原文地址:https://www.cnblogs.com/YingZhixin/p/6562445.html
Copyright © 2011-2022 走看看