您的位置:首页 > 其它

座位调整问题【解决思路及求证】

2010-12-02 16:45 901 查看
近来无聊,开始做ACM练练脑子,恰好看到百度竞赛的一道《座位调整》题目:

题目描述:

百度办公区里到处摆放着各种各样的零食。百度人力资源部的调研发现,员工如果可以在自己喜欢的美食旁边工作,工作效率会大大提高。因此,百度决定进行一次员工座位的大调整。

调整的方法如下:

1 . 首先将办公区按照各种零食的摆放分成 N 个不同的区域。(例如:可乐区,饼干区,牛奶区等等)。

2 . 每个员工对不同的零食区域有不同的喜好程度(喜好程度度的范围为 1 — 100 的整数, 喜好程度越大表示该员工越希望被调整到相应的零食区域)。

3 . 由于每个零食区域可以容纳的员工数量有限,人力资源部希望找到一个最优的调整方案令到总的喜好程度最大。

数据输入:

第一行包含两个整数 N , M ,( 1<=N , M<=300 )。分别表示 N 个区域和 M 个员工。

第二行是 N 个整数构成的数列 a ,其中 a[i] 表示第 i 个区域可以容纳的员工数, (1<=a[i]<=M , a[1]+a[2]+..+a
=M) 。

紧接着是一个 M*N 的矩阵 P , P ( i , j )表示第 i 个员工对第 j 个区域的喜好度。

答案输出:

对于每个测试数据,输出可以达到的最大的喜好程度。

输入样例

3 3

1 1 1

100 50 25

100 50 25

100 50 25

输出样例

175

数据解释:此数据只存在一种安排方法,三个员工分别安置在三个区域。最终的喜好程度为 100+50+25=175

想了想,得出如下C#程序(我是C#初学者):

using System;
using System.Collections.Generic;

namespace ACM_2
{
class Program
{
static void Main()
{
try
{
var program = new Program();
string inputLine1 = Console.ReadLine();

int areas = 0;
int staffs = 0;

if(inputLine1 != null)
{
areas = Int32.Parse(inputLine1.Split(' ')[0]);
staffs = Int32.Parse(inputLine1.Split(' ')[1]);
}

var matrix = new int[staffs, areas];
var limitMatrix = new int[areas];

string inputLine2 = Console.ReadLine();
if(inputLine2 != null)
{
//set the limit of each area
for (int x = 0; x < inputLine2.Split(' ').Length;x++ )
{
limitMatrix[x] = Int32.Parse(inputLine2.Split(' ')[x]);
}
for (int i = 0; i < staffs; i++)
{
string loveAreas = Console.ReadLine();
if (loveAreas != null)
{
if (loveAreas.Split(' ').Length != areas)
{
Console.Error.WriteLine("Num of areas error in staffs.");
}
else
{
string[] love = loveAreas.Split(' ');
for (int j = 0; j < love.Length; j++)
{
matrix[i, j] = Int32.Parse(love[j]);
}
}
}
}

// now have got all the values in the matrix, start to caculate
// for each areas

var maxChoose = new int[areas];
for (int j = 0; j < areas;j++ )
{
var staffList = new List<bool>();
for (int i = 0; i < staffs;i++ )
{
staffList.Add(false);
}
var selected = new int[areas];

// for each loop,initual the marked list of each staff member
int firstStaff = program.GetLocalMaxStaff(staffList, matrix, staffs, areas, j);
maxChoose[j] = matrix[firstStaff,j];
program.MarkedAfterChoose(ref selected,ref staffList,j,firstStaff);

for (int l = 0; l < staffs -1;l++ )
{
// store the max matrix value in this circle
int max = 0;
int areaNo = -1;
int staffNo = -1;

for (int k = 0; k < areas; k++)
{
//get the max permitted staff in appointed area
if (selected[k] < limitMatrix[k])
{
// compare first,not real choose
int localStaff = program.GetLocalMaxStaff(staffList, matrix, staffs, areas, k);
int areaMax = matrix[localStaff, k];
if (areaMax > max)
{
max = areaMax;
areaNo = k;
staffNo = localStaff;
}
}
}

// after compare all of the max value, choose the best one and marked
program.MarkedAfterChoose(ref selected,ref staffList,areaNo,staffNo);
maxChoose[j] += max;
}
}

int finalMax = -1;
foreach (int t in maxChoose)
{
if(t>finalMax)
{
finalMax = t;
}
}

Console.WriteLine("Max Value:{0}",finalMax);
Console.ReadLine();
}
}catch(Exception e)
{
Console.Error.WriteLine(e.Message);
}
}

/// <summary>
/// when chosen,mark the status
/// </summary>
/// <param name="selected"></param>
/// <param name="staffList"></param>
/// <param name="areaNo"></param>
/// <param name="staff"></param>
public void MarkedAfterChoose(ref int[] selected, ref List<bool> staffList, int areaNo,int staff)
{
selected[areaNo]++;
staffList[staff] = true;
}

/// <summary>
/// get local max of each area
/// </summary>
/// <param name="staffList"></param>
/// <param name="matrix"></param>
/// <param name="staffs"></param>
/// <param name="areas"></param>
/// <param name="areaNo"></param>
/// <returns></returns>
public int GetLocalMaxStaff(List<bool>staffList,int[,] matrix,int staffs,int areas,int areaNo)
{
int max = 0;
int staff = -1;
for(int i= 0; i< staffs;i++)
{
if(!staffList[i] && matrix[i,areaNo] > max)
{
max = matrix[i, areaNo];
staff = i;
}
}
return staff;
}
}
}

跑了几个测试用例,好像都能通过,程序算法描述如下:

1、以每个AREA为分割进行几次独立的筛选,从喜好程序最大的人员进行选择,并将已被选择的人员进行标记以免下次被重复选择。

2、对于每次独立的筛选,分为M(员工人数)轮选择,以达到所有的员工都能对号入座。

3、对于每次独立筛选的每一轮,分为N(区域数目)种情况,每种情况代表从不同的AREA进行选择(AREA考虑容纳人数的限制,如果该AREA容纳人数已满,即selected[k] = limitMatrix[k]时,跳过该区域),每一轮结束取最大值,抛弃其它值。

4、所有独立筛选完成后,取最大值,即为最终最大值,抛弃其它值。

以下我的测试用例:

CASE 1:
3 3
1 1 1
100 50 25
100 50 25
100 50 25

CASE 2:
3 4
1 2 1
100 50 25
50 25 100
25 100 50
100 100 100

CASE 3:
3 3
1 1 1
100 99 1
1 50 45
9 10 1

CASE 4:
3 3
1 1 1
100 50 80
100 70 30
50 100 30

用例都能通过,但我对这种算法还是存在疑问,我的算法都是从最大值开始取,那么如果存在这么一种情况:【当所有的区域都未取最大值时,所得最后结果为最大值】,那我的算法就是错误的,求证!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: