洛谷 P1056 排座椅

題目描述
上課的時候總會有一些同學和前後左右的人交頭接耳,這是令小學班主任十分頭疼的一件事情。不過,班主任小雪發現了一些有趣的現象,當同學們的座次確定下來之後,只有有限的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(手動微笑),代碼一粘多就格式全亂掉,編輯都編輯不了只能刷新,一刷新前面寫的題解就全得重寫(手動微笑)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章