UVa Problem 10249 The Grand Dinner (丰盛的晚餐)

// The Grand Dinner (丰盛的晚餐) // PC/UVa IDs: 111007/10249, Popularity: C, Success rate: high Level: 4 // Verdict: Accepted // Submission Date: 2011-10-08 // UVa Run Time: 0.092s // // 版权所有(C)2011,邱秋。metaphysis # yeah dot net // // [Problem Description] // Each team participating in this year’s ACM World Finals is expected to attend // the grand banquet arranged for after the award ceremony. To maximize the amount // of interaction between members of different teams, no two members of the same // team will be allowed to sit at the same table. // // Given the number of members on each team (including contestants, coaches, // reserves, and guests) and the seating capacity of each table, determine whether // it is possible for the teams to sit as described. If such an arrangement is // possible, output one such seating assignment. If there are multiple possible // arrangements, any one is acceptable. // // [Input] // The input file may contain multiple test cases. The first line of each test // case contains two integers, 1 ≤ M ≤ 70 and 1 ≤ N ≤ 50, denoting the number of // teams and tables, respectively. The second line of each test case contains M // integers, where the ith integer mi indicates the number of members of team i. // There are at most 100 members of any team. The third line contains N integers, // where the jth integer nj , 2 ≤ nj ≤ 100, indicates the seating capacity of // table j. // // A test case containing two zeros for M and N terminates the input. // [Output] // For each test case, print a line containing either 1 or 0, denoting whether // there exists a valid seating arrangement of the team members. In case of a // successful arrangement, print M additional lines where the ith line contains // a table number (from 1 to N ) for each of the members of team i. // // [Sample Input] // 4 5 // 4 5 3 5 // 3 5 2 6 4 // 4 5 // 4 5 3 5 // 3 5 2 6 3 // 0 // // [Sample Output] // 1 // 1 2 4 5 // 1 2 3 4 5 // 2 4 5 // 1 2 3 4 5 // // [解题方法] // 此题有两种解法,一种是简单的贪心法,一种是较复杂的图论网络最大流法。 // // 贪心法采用如下策略:先将人数按降序排列,从编号为 1 的桌子开始安排座位,安排完后,安排下一队。若 // 能安排完所有人,则输出 1 和安排方案,若不能安排则输出 0,其中明显不能安排的,如某队人数大于桌子 // 数,参赛队伍数或桌子数为 0 等特殊情况,可以预先处理(虽然可以得到正确答案,但是贪心法的正确性如 // 何证明?可以通过网络最大流来证明吗?)。 // // 网络流解法:源点 source 和每支参赛队伍之间边的容量为参赛队伍人数,每支队伍到桌子之间边的容量为 // 1,每张桌子到汇点 sink 边的容量为桌子的座位数,然后使用网络流算法求最大流,如果最大流等于参赛队 // 伍总人数,则满足条件,输出方案,否则不满足条件,输出 0。可以使用宽度优先遍历的 Ford-Fullerson // 增广路方法,又名 Edmonds-Karp 算法,算法效率为 O(V*E*E),后续博文会给出。 #include <iostream> #include <algorithm> #include <cstring> using namespace std; #define MAXTEAMS 70 // 最大参赛队伍数。 #define MAXTABLES 50 // 桌子最大数。 #define UNSOLVABLE 0 #define SOLVABLE 1 struct team { int number; // 参赛队伍编号。 int nmembers; // 参赛队伍人数。 }; // 比较函数,参数队伍人数多的排前面。 bool cmp(team x, team y) { return x.nmembers > y.nmembers; } int main(int ac, char *av[]) { team teams[MAXTEAMS]; // 各参赛队编号,人数。 int capacity[MAXTABLES]; // 桌子的座位数。 int nteams, ntables, ntemp; // 队伍数,桌子数,总人数。 bool seat[MAXTABLES][MAXTEAMS]; // 记录座位安排方案。 while (cin >> nteams >> ntables, nteams || ntables) { // 读入参赛队人数并找参赛队的最大人数。 int maxMembers = 0; for (int i = 0; i < nteams; i++) { cin >> ntemp; if (maxMembers < ntemp) maxMembers = ntemp; teams[i].number = i; teams[i].nmembers = ntemp; } // 读入桌子座位数量。 for (int i = 0; i < ntables; i++) cin >> capacity[i]; // 若参赛队伍数为 0,则直接输出存在,但是不用输出具体方案,因为所有桌子无人坐。 if (nteams == 0) { cout << SOLVABLE << "\n"; continue; } // 若桌子数为 0 或者参赛队伍中某队人数超过桌子数,则无法安排。 if (ntables == 0 || maxMembers > ntables) { cout << UNSOLVABLE << "\n"; continue; } // 将参赛队伍按人数多少从大到小排列。 sort(teams, teams + nteams, cmp); // 贪心法安排座位,若某队无法安排,则无安排方案。 bool sitting = true; memset(seat, false, sizeof(seat)); for (int i = 0; i < nteams; i++) { ntemp = teams[i].nmembers; for (int j = 0; j < ntables && ntemp; j++) if (capacity[j]) { ntemp--; capacity[j]--; seat[j][teams[i].number] = true; } // 若经过一轮安排后,剩余人数不为 0 则无法安排。 if (ntemp) { sitting = false; break; } } cout << (sitting ? SOLVABLE : UNSOLVABLE) << "\n"; if (sitting) { for (int i = 0; i < nteams; i++) { int blank = 0; for (int j = 0; j < ntables; j++) if (seat[j][i]) cout << (blank++ ? " " : "") << (j + 1); cout << "\n"; } } } return 0; }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值