題目描述
上課的時候總會有一些同學和前後左右的人交頭接耳,這是令小學班主任十分頭疼的一件事情。不過,班主任小雪發現了一些有趣的現象,當同學們的座次確定下來之後,只有有限的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條粗線的位置表示通道,圖示的通道劃分方案是唯一的最佳方案。
這題一開始給看錯題目,看成有唯一解能分割所有學生。其實是讓找出最優解能分割最多的學生。
貪心+排序+模擬
用兩個數組存一下每行/每列的人數,然後在分割次數內找出人數最多的幾行/幾列,用另兩個數組記錄找到的這幾行的行號/列號,最後分別輸出即可。
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#include<string>
using namespace std;
int main()
{
int m, n, k, l, d;//m行n列,k條橫向通道,l條縱向通道,d個學生交頭接耳
int k1, l1;
int x[2], y[2];//學生座標
int a[1005], b[1005];//存每行/每列有幾個學生
int a1[1005], b1[1005];//存學生最多的行/列的位置
cin >> m >> n >> k >> l >> d;
k1 = k, l1 = l;
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
memset(a1, 0, sizeof(a1));
memset(b1, 0, sizeof(b1));
for (int i = 1; i <= d; i++)
{
cin >> x[0] >> y[0] >> x[1] >> y[1];
if (x[0] == x[1])//如果橫座標相等,記錄縱列人數
{
int minn = min(y[0], y[1]);
b[minn]++;
}
else if (y[0] == y[1])//如果縱座標相等,記錄橫行人數
{
int minn = min(x[0], x[1]);
a[minn]++;
}
}
int maxn, pos;
for (int i = 0; i < k; i++)//橫向可加的通道
{
maxn = 0, pos = 0;//更新最大值,及其位置
for (int j = 1; j <= m; j++)//從第一行到第m行遍歷
{
if (a[j] > maxn)
{
maxn = a[j];//更新最大值
pos = j;//記錄最大值的位置
}
}
a1[pos] = 1;//標記行號
a[pos] = 0;//將最大值清空,使得下一次找到的是第二大的
}
for (int i = 0; i < l; i++)//縱向可加的通道
{
maxn = 0, pos = 0;//更新最大值,及其位置
for (int j = 1; j <= n; j++)//從第一列到第n列遍歷
{
if (b[j] > maxn)
{
maxn = b[j];//更新最大值
pos = j;//記錄最大值的位置
}
}
b1[pos] = 1;//標記該行號
b[pos] = 0;//將最大值清空,使得下一次找到的是第二大的
}
for (int i = 0; k1>0; i++)
{
if (k1 == k&&a1[i])
{
cout << i;
k1--;
}
else if(a1[i])
{
cout << " " << i;
k1--;
}
}
cout << endl;
for (int i = 0; l1 >0; i++)
{
if (l1 == l&&b1[i])
{
cout << i;
l1--;
}
else if(b1[i])
{
cout << " " << i;
l1--;
}
}
cout << endl;
//system("pause");
return 0;
}
吐槽一句csdn(手動微笑),代碼一粘多就格式全亂掉,編輯都編輯不了只能刷新,一刷新前面寫的題解就全得重寫(手動微笑)