首页 > 试题广场 >

排座椅

[编程题]排座椅
  • 热度指数:3290 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 50M,其他语言100M
  • 算法知识视频讲解
\hspace{15pt}教室内共有 nm 列座位,坐在第 i 行第 j 列同学的位置记为 (i,j)

\hspace{15pt}为了方便进出,班主任计划设置 k横向通道(贯穿整列的水平通道)与 l纵向通道(贯穿整行的竖直通道)。通道位于相邻两行(或两列)之间。

\hspace{15pt}班主任记录了 d 对经常交头接耳的同学,他们的位置 (x_i,y_i)(p_i,q_i) 保证相邻(上下或左右)。她希望通过合理放置通道,使尽可能多的"交头接耳"对被通道隔开。

\hspace{15pt}现请你输出唯一的最优方案,在该方案下,仍未被通道隔开的"交头接耳"对的数量最少。

输入描述:
\hspace{15pt}第一行输入五个整数 n,m,k,l,d\left(2\leqq n,m\leqq 10^3;\ 0<k<n;\ 0<l<m;\ 0< d \leqq 2\times\min\{n\times m,2\times10^3\}\right)

\hspace{15pt}接下来 d 行,每行输入四个整数 x_i,y_i,p_i,q_i,表示坐标 (x_i,y_i)(p_i,q_i) 的两位同学会交头接耳,且两坐标上下相邻或左右相邻。

\hspace{15pt}保证最优方案存在且唯一。


输出描述:
\hspace{15pt}第一行输出 k 个严格递增的整数 a_1,a_2,\dots,a_k\left(1\leqq a_1<\dots<a_k\leqq n-1\right),在行 a_ia_i+1 之间设置横向通道。

\hspace{15pt}第二行输出 l 个严格递增的整数 b_1,b_2,\dots,b_l\left(1\leqq b_1<\dots<b_l\leqq m-1\right),在列 b_ib_i+1 之间设置纵向通道。
示例1

输入

4 5 1 2 3
4 2 4 3
2 3 3 3
2 5 2 4

输出

2
2 4

说明

\hspace{15pt}该样例如下图所示,蓝底斜线方格为第一对交头接耳的同学,绿底带叉方格为第二对交头接耳的同学,粉底带星方格为第三对交头接耳的同学。粗线代表通道。该划分方案为唯一最优方案。

示例2

输入

2 2 1 1 4
1 1 1 2
1 1 2 1
2 1 2 2
1 2 2 2

输出

1
1
#include <stdio.h>
#include <stdlib.h>
//既然是贪心,那就找每一列和每一行的交头接耳的有多少对。优先选,某一行或者某一列交头接耳人数最多的给干掉就可以了,实现所谓的贪心。直到用完所有通道,好像也还行
//大佬的思路看来跟你想的一样

typedef struct
{
    int pos; //某一行或者某一列
    int count;  //记录这一行或者这一列上有多少对交投杰尔的同学
} hang_lie;

int compare(const void *p1,const void *p2)
{
    //如果相同应该按序号升序
    hang_lie temp1=(*(hang_lie*)p1);
    hang_lie temp2=(*(hang_lie*)p2);

    if(temp1.count<temp2.count)
    {
        return 1;
    }else if (temp1.count>temp2.count) {
        return -1;
    }else {
        //如果相同应该按序号升序
        if(temp1.pos<temp2.pos)
        {
            return -1;
        }else {
            return 1;
        }
    }

    return 0;//降序
}

int compare2(const void *p1,const void *p2)
{
    return (*(hang_lie*)p1).pos-(*(hang_lie*)p2).pos;//序号升序
}

int main() {

    int n, m,k,l,d;  //k行,l列
    scanf("%d %d %d %d %d",&n,&m,&k,&l,&d);
    
    //创建两个数组分别记录每行每列上有多少对交投杰尔的同学
    hang_lie* hang=malloc(sizeof(hang_lie)*n); //创建n行
    hang_lie* lie=malloc(sizeof(hang_lie)*m); //创建m列
    
    for (int i=0; i<n; i++) {  //初始化数值
        hang[i].pos=i+1;
        hang[i].count=0;
    }
    for (int i=0; i<m; i++) {
        lie[i].pos=i+1;
        lie[i].count=0;
    }

    //开始记录每行每列有多少对交头接耳同学
    for (int i=0; i<d; i++) {
        int x,y,p,q; 
        scanf("%d %d %d %d",&x,&y,&p,&q);

        //根据位置判断这两个同学是在行上还是列上交投接耳
        if (x==p) {   //如果纵坐标相同说明在行上交头
            lie[y<q?y-1:q-1].count++;//在这个列上记录一对 ,搞错了应该是用用小的那个列作为下标,而不是用x
        }else if (y==q){
            hang[x<p?x-1:p-1].count++;//在这个行上记录一对,应该是用小的另一个坐标那个作为下标
        }
    }

    //查看统计结果
    // printf("hang:\n");
    // for (int i=0; i<n; i++) {  //初始化数值
    //     printf("%d=%d \n",hang[i].pos,hang[i].count);
    // }
    // printf("列:\n");
    // for (int i=0; i<m; i++) {
    //     printf("%d=%d \n",lie[i].pos,lie[i].count);
    // }

    //排序后选最大的分割
    qsort(hang, n, sizeof(hang_lie), compare);
    qsort(lie, m, sizeof(hang_lie), compare);
    
    //行选前k个,列选前L个进行分割即可
    //还得按序号排序一次
    qsort(hang, k, sizeof(hang_lie), compare2);  //注意用的是compare2的排序
    qsort(lie, l, sizeof(hang_lie), compare2);
    
    for (int i=0; i<k; i++) {  //行选前k个,列选前L个输出即可
        printf("%d ",hang[i].pos);
    }
    printf("\n");
    for (int i=0; i<l; i++) {  //行选前k个,列选前L个输出即可
        printf("%d ",lie[i].pos);
    }

    return 0;
}

发表于 2025-10-10 17:25:01 回复(0)