http://ybt.ssoier.cn:8088/problem_show.php?pid=1943
【题目描述】
上课的时候总有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情。不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的D对同学上课时会交头接耳。同学们在教室中坐成了M行N列,坐在第ii行第jj列的同学的位置是(i,j),为了方便同学们进出,在教室中设置了K条横向的通道,L条纵向的通道。于是,聪明的小雪想到了一个办法,或许可以减少上课时学生交头接耳的问题:她打算重新摆放桌椅,改变同学们桌椅间通道的位置,因为如果一条通道隔开了两个会交头接耳的同学,那么他们就不会交头接耳了。
请你帮忙给小雪编写一个程序,给出最好的通道划分方案。在该方案下,上课时交头接耳的学生的对数最少。
【输入】
第一行,有55个用空格隔开的证书,分别是M,N,K,L,D(2≤N,M≤1000,0≤K<M,0≤L<N,D≤2000)M,N,K,L,D(2≤N,M≤1000,0≤K<M,0≤L<N,D≤2000)。
接下来D行,每行有4个用空格隔开的整数。第i行的4个证书Xi,Yi,Pi,OiXi,Yi,Pi,Oi,表示坐在位置(Xi,Yi)与(Pi,Oi)的两个同学会交头接耳(输入保证他们前后相邻或者左右相邻)。
输入数据保证最优秀方案的唯一性。
【输出】
共两行。
第一行包含KK个整数,a1,a2……ak,表示第a1行和a1+1行之间、第a2行和第a2+1行之间、…、第aK行和第aK+1行之间要开辟通道,其中ai<ai+1,每两个整数之间用空格隔开(行尾没有空格)。
第二行包含L个整数,b1b2……bL,表示第b1列和b1+1列之间,第b2列和b2+1列之间、…、第bL列和第bL+1列之间要开辟通道,其中bi<bi+1,每两个整数之间用空格隔开(行尾没有空格)。
【输入样例】
4 5 1 2 3
4 2 4 3
2 3 3 3
2 5 2 4
【输出样例】
2
2 4
题目有点长,但是本题考察的是贪心+排序;需要解决的问题是:找到横排的前k个、纵排的前l个;
- 怎样找到横排的前k个,显然就是横排说话同学最多的横排,才最需要隔开,所以需要找横排说话同学最多的前k个;
- 怎样找到纵排的前l个,同理。
方法一:贪心+快排
#include<bits/stdc++.h>
using namespace std;
#define N 1005
int aK[N], aL[N];//横排的前k个、纵排的前l个
int a1[N], b1[N];//横纵坐标出现的次数
int main(){
int m, n, k, l, d, x1, y1, x2, y2;
cin >> m >> n >> k >> l >> d;
for(int i=1; i<=d; i++){//统计横纵坐标出现的次数
cin >> x1 >> y1 >> x2 >> y2;
if(x1 == x2)
b1[(y1>y2)?y2:y1]++;
else if(y1 == y2)
a1[(x1>x2)?x2:x1]++;
}
for(int i=1; i<=k; i++){//通过比较大小,拿到a1数组(横坐标)中的前k值
int mmax = 0, x;
for(int j=1; j<=m; j++){
if(a1[j] > mmax)
mmax = a1[j], x = j;
}
aK[i] = x;
a1[x] = 0;
}
for(int i=1; i<=l; i++){//通过比较大小,拿到b1数组(纵坐标)中的前l值
int mmax = 0, x;
for(int j=1; j<=n; j++){
if(b1[j] > mmax)
mmax = b1[j], x = j;
}
aL[i] = x;
b1[x] = 0;
}
sort(aK+1, aK+k+1);
sort(aL+1, aL+l+1);
for(int i=1; i<=k; i++)
cout << aK[i] << " ";
cout << endl;
for(int i=1; i<=l; i++)
cout << aL[i] << " ";
cout << endl;
return 0;
}
方法二:贪心+结构体排序
#include<bits/stdc++.h>
using namespace std;
#define N 1005
struct node{
int t, x;
}aK[N], bL[N];
bool cmp_big(node p, node q){
return p.t > q.t;
}
bool cmp_small(node p, node q){
return p.x < q.x;
}
int main(){
int m, n, k, l, d, x1, y1, x2, y2;
cin >> m >> n >> k >> l >> d;
for(int i=1; i<=d; i++){
cin >> x1 >> y1 >> x2 >> y2;
if(x1 == x2){
bL[(y1>y2)?y2:y1].t++;//t:出现次数times
bL[(y1>y2)?y2:y1].x = (y1>y2)?y2:y1;//x:出现的数
}
else if(y1 == y2){
aK[(x1>x2)?x2:x1].t++;
aK[(x1>x2)?x2:x1].x = (x1>x2)?x2:x1;
}
}
sort(aK+1, aK+m+1, cmp_big);//按照出现次数从大到小排序,找到前k个
sort(bL+1, bL+n+1, cmp_big);//按照出现次数从大到小排序,找到前l个
sort(aK+1, aK+k+1, cmp_small);//将前k个按照x(数)从小到大排序
sort(bL+1, bL+l+1, cmp_small);//将前l个按照x(数)从小到大排序
for(int i=1; i<=k; i++)
cout << aK[i].x << " ";
cout << endl;
for(int i=1; i<=l; i++)
cout << bL[i].x << " ";
cout << endl;
return 0;
}