搜索入门练习题7 最高效益和 题解

题目出处:《信息学奥赛一本通》例5.6

题目描述

设有A、B、C、D、E五人从事J1、J2、J3、J4、J5五项工作,每人只能从事一项,他们的效益如下所示。

? J1 J2 J3 J4 J5
A 13 11 10 4 7
B 13 10 10 8 5
C 5 9 7 7 4
D 15 12 10 11 5
E 10 11 8 8 4

每人选择五项工作中的一项,在各种选择的组合中,找到效益最高的一组输出。

题目分析

这道题目其实就是“全排列”问题的变形题,我们可以使用深度优先搜索枚举出所有排列,从而找出和最大的那个排列。
书上的算法分析:

  1. 用数组 \(f\) 储存搜索中工作选择的方案;数组 \(g\) 存放最优的工作选择方案;数组 \(p\) 用于表示某项工作有没有被选择。
  2. (1)选择 \(p(i) = 0\) 的第 \(i\) 项工作;
    (2)判断效益是否高于 \(maxv\) (这里的 \(maxv\) 用于记录最高的效益和),若高于则更新 \(g\) 数组及 \(maxv\) 的值。
  3. 搜索策略:回溯法(深度优先搜索dfs)。

然后我就用这种思想来实现这道题目,实现代码如下:

#include <bits/stdc++.h>
using namespace std;
int a[][5] = {  // 数组a用于反映任务效益
    13, 11, 10, 4, 7,
    13, 10, 10, 8, 5,
    5, 9, 7, 7, 4,
    15, 12, 10, 11, 5,
    10, 11, 8, 8, 4
};  // a[i][j]表示第i个人做第j项工作的效益
// f[i] 对应当前第i个人选择方案的编号
// g[i] 对应最高效益的第i个人选择方案的编号
// maxv 对应最高效益和
// tmp用于存储 f 对应的当前效益和
// p[i] 用于表示第i项工作是否已分配,
// p[i]为true说明第i项工作已经分配,为false说明第i项工作还没有分配
// 注意,这里人的编号以及人物的编号都从0开始
int f[5], g[5], maxv, tmp;
bool p[5];
// check函数用于判断f数组当前方案是否比g数组的方案更优
bool check() {
    tmp = 0;          //
    for (int i = 0; i < 5; i ++)    // 因为分配给第i个人的工作编号是p[i],
        tmp += a[i][ f[i] ];        // 所以tmp需要加上 a[i][ p[i] ]
    return tmp > maxv;
}
// update函数用于更新 g 和 maxv
void update() {
    maxv = tmp;
    for (int i = 0; i < 5; i ++) g[i] = f[i];
}
// dfs函数用于搜过第id个人对应的工作编号
void dfs(int id) {
    if (id == 5) { // 边界条件,说明5个人的工作都分配好了
        if (check()) update();
        return;
    }
    for (int i = 0; i < 5; i ++) {  // i用于遍历工作
        if (p[i] == false) {    // p[i]为false说明第i项工作还没有人做
            f[id] = i;      // 尝试让第id个人做第i项工作
            p[i] = true;    // 同时标记第i项工作已经有人做了
            dfs(id+1);        // 为第id+1个人分配工作
            p[i] = false;   // 回溯回来后我们要确保p[i]重新置为false
        }
    }
}
// output函数用于输出maxv和最高效益方案g
void output() {
    cout << maxv << endl;
    for (int i = 0; i <5; i ++)
        printf("%5d", g[i]+1);  // g[i]从0到4,g[i]+1从1到5
    cout << endl;
}
int main() {
    dfs(0);
    output();
    return 0;
}

原文地址:https://www.cnblogs.com/zifeiynoip/p/11450710.html

时间: 2024-10-05 05:47:55

搜索入门练习题7 最高效益和 题解的相关文章

搜索入门练习题4 数的拆分 题解

题目描述 任何一个大于 \(1\) 的自然数 \(n\) ,总可以拆分成若干个小于 \(n\) 的自然数之和.当 \(n = 4\) 时,总共有 \(4\) 种拆分方法: \(4=1+1+1+1\) \(4=1+1+2\) \(4=1+3\) \(4=2+2\) 现在给你一个数 \(n(1 \le n \le 20)\) ,请按顺序输出 \(n\) 的所有拆分方案. 输入格式 输入包含一个整数 \(n(1 \le n \le 20)\) . 输出格式 输出 \(n\) 的所有拆分方案,每种方案占

搜索入门练习题5 八皇后问题 题解

题目来源:<信息学奥赛一本通>例5.4 题目描述 要在国际象棋棋盘(\(8 \times 8\) 的棋盘)中放 \(8\) 个皇后,使任意两个皇后都不能互相吃.(提示:皇后能吃同一行.同一列.同一对角线的任意棋子.) 输出格式 输出一个整数,用于表示八皇后问题的放置方案. 题目分析 首先我们用 \((x,y)\) 来表示棋盘上第 \(x\) 行第 \(y\) 列的格子的坐标. 那么,两个皇后 \((x_1,y_1)\) 和 \((x_2,y_2)\) 会互相攻击当且仅当满足如下条件之一: 在同

搜索入门练习题2 全排列 题解

题目出处:课程=>搜索1=>题目A 题目描述 给定一个正整数 \(n\) ,按照递增顺序打印数字 \(1\) 到 \(n\) 的所有排列. 输入格式 一个整数 \(n(1 \le n \le 7)\) . 输出格式 按照递增顺序输出 \(n\) 个数的所有排列,每行代表一组排列, \(n\) 个数两两之间有一个空格分隔. 样例输入 3 样例输出 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1 问题分析 这是一道搜索的题目. 我们知道搜索就是状态到状态之间的转换,其本质是

搜索入门练习题3 全组合 题解

题目出处:<信息学奥赛一本通>例5.2. 题目描述 设有 \(n\) 个数的集合 \(\{1,2,...,n\}\) ,从中任意取出 \(r\) 个数进行排列 \((r \le n)\) ,试列出所有的排列. 输入格式 输入包含两个正数 \(n,r(1 \le r \le n \le 10)\) 输出格式 输出从 \(n\) 个数的集合中选出 \(r\) 个数的所有组合,每个组合方案占一行.对于每个组合,按照从小到大的顺序输出组合中的所有元素,两两之间有一个空格分隔. 样例输入 3 2 样例输

搜索入门练习题1 素数环 题解

题目出处:<信息学奥赛一本通>例5.1. 题目描述 素数环:从 \(1\) 到 \(n(2 \le n \le 20)\) 这 \(n\) 个数摆成一个环,要求相邻的两个数的和是一个素数. 输入格式 输入包含一个整数 \(n(2 \le n \le 20)\) . 输出格式 按字典序从小到大的顺序输出所有排列方案,每个排列方案占一行.每行的 \(n\) 个数之间由一个空格分隔. 样例输入 2 样例输出 1 2 2 1 问题分析 很明显,这是一道可以用搜索解决的问题,我们可以采用"回溯

搜索入门之dfs--经典的迷宫问题解析

今天来谈一下dfs的入门,以前看到的dfs入门,那真的是入门吗,都是把dfs的实现步骤往那一贴,看完是知道dfs的步骤了,但是对于代码实现还是没有概念.今天准备写点自己的心得,真的是字面意思--入门. DFS,即深度优先搜索,是一种每次搜索都向尽可能深的地方去搜索,到达尽头时再回溯进行其他结点去搜索的搜索策略.形象的说,这是一种“不撞南墙不回头”的策略. 其实也就是遍历,只不过不像一个线性数组的遍历那么直观罢了.说到回溯,每次看到这个词我都得思考一会,到底是怎么用栈进行回溯的呢?今天实际操作了一

搜索:A - Tempter of the Bone题解

问题描述: The doggie found a bone in an ancient maze, which fascinated him a lot. However, when he picked it up, the maze began to shake, and the doggie could feel the ground sinking. He realized that the bone was a trap, and he tried desperately to get

POJ 1579 Function Run Fun 【记忆化搜索入门】

题目传送门:http://poj.org/problem?id=1579 Function Run Fun Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20560   Accepted: 10325 Description We all love recursion! Don't we? Consider a three-parameter recursive function w(a, b, c): if a <=

【小白入门向】tarjan算法+codevs1332题解报告

一.[前言]关于tarjan tarjan算法是由Robert Tarjan提出的求解有向图强连通分量的算法. 那么问题来了找蓝翔!(划掉)什么是强连通分量? 我们定义:如果两个顶点互相连通(即存在A到B和B到A的通路),则称这两个点强连通.对于一个有向图G,若是G中任意两点都强连通,则称G是一个强连通图.有向图的极大强连通子图,称为该图的强连通分量. 对于下图,{1,2,3,4}.{5}.{6}分别是它的强连通分量. 那么tarjan是如何找到这些强连通分量的呢? 说白了tarjan就是dfs