赏月斋源码共享计划 第二期
需求描述:
有m个任务,第i个任务需要xi时间去完成,难度等级为yi
有n台机器,每台机器最长工作时间为zi,机器等级wi
一个任务只能交给一台机器,且如果机器的最长工作时间小于任务所需时间,则不能完成
若完成任务,获得收益为200*xi+3*yi
一台机器一天只能完成一个任务,若机器等级小于任务难度等级,则不能完成
想尽可能多地完成任务,即完成任务数最大,找到收益最大的方案
代码实现:
# include <bits/stdc++.h> using namespace std; # define LL long long const int maxn = 1e5 + 10; struct node { int x, y; }e[maxn], f[maxn]; int cnt[105]; int cmp(node a, node b) { //cmp()用于排序,返回a和b按字典排序的大小 if (a.x == b.x) { return a.y > b.y; } return a.x > b.x; } int main(void) { int m, n; scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) scanf("%d%d", &e[i].x, &e[i].y); //e表示机器 for (int i = 0; i < m; i++) scanf("%d%d", &f[i].x, &f[i].y);//f表示任务 sort(e, e + n, cmp); sort(f, f + m, cmp); //排序 int num = 0; LL ans = 0; memset(cnt, 0, sizeof(cnt)); //赋初值 int i, j, k; for (i = 0, j = 0; i < m; i++) { while (j < n && e[j].x >= f[i].x) { cnt[e[j].y]++; j++; } for (k = f[i].y; k <= 100; k++) { if (cnt[k]) { num++; cnt[k]--; ans = ans + 200 * f[i].x + 3 * f[i].y; break; } } } /************************************************************************/ /* while循环先把满足时间条件的机器筛选出来(机器、任务都按从大到小排序) 选出来满足时间条件的机器 分别记下他们的难度 cnt[i]=t 表示选出来t个难度为i的机器 接下来,while后边的for循环用来选择难度条件 从任务i的难度k=f[i].y开始依次递增k++ 第一个满足if条件的k就是最小的k(最节约机器难度) 即:尽量先用满足条件的机器中支持难度小的机器*/ /************************************************************************/ printf("%d %ld\n", num, ans); return 0; }
解决方案二:
分析:
收益只与完成的任务x、y有关,且x、y越大,获得的收益越大,所以要优先完成x更大的任务,若x相等,则要优先完成y大的任务。
为保证上述完成要求,我们可以将任务的x按从大到小排序,若x相同,根据y从大到小排序,排序完成后,再给任务分配机器。
当有多台机器符合x条件,选择y满足条件的最小的wi。
#include<cstdio> #include<cstring> #include<algorithm> #define Max 100010 #define LL long long using namespace std; struct A { int x; int y; }t[Max], m[Max]; bool cmp(A a, A b) { if(a.x != b.x)return a.x > b.x; return a.y > b.y; } int main() { int N, M; scanf("%d %d", &N, &M); for(int i = 0; i < N; i++) scanf("%d %d", &m[i].x, &m[i].y); for(int j = 0; j < M; j++) scanf("%d %d", &t[j].x, &t[j].y); sort(t, t + M, cmp); sort(m, m + N, cmp); /*for(int i = 0; i < N; i++) printf("%d %d\n", t[i].x, t[i].y);*/ LL sum = 0; int count = 0; int mark[Max]={0}; int j = 0; for(int i = 0; i < M; i++) { //每台机器只能用一次,所以分配下一个任务时,j从上一个任务之后开始考虑,j不用归0 //由于任务是按从到大小排列的,因此满足上一任务要求的机器一定满足下一任务要求 while(j < N && m[j].x >= t[i].x) { mark[m[j].y]++;//机器对应等级加1,表示满足该任务时长下,符合等级要求的可用的机器数 j++; } for(int k = t[i].y; k <= 100; k++)//从符合等级要求的等级最低的机器开始分配 { if(mark[k]) { mark[k]--; count++; sum += (LL)(200 * t[i].x + 3 * t[i].y); //printf("sum = %lld\n", sum); break; } } } printf("%d %lld\n", count, sum); return 0; }
解决方案三:
import java.util.Arrays; import java.util.Scanner; class A implements Comparable<A>{ int x; int y; public int compareTo(A o) { // TODO Auto-generated method stub if(this.x>o.x) return -1;//返回-1表示当前对象在前,即由高到底排序 ;return 1则为由低到高排 else if(this.x<o.x) return 1; else{ //如果x的值一样,则比较y的大小 if(this.y>o.y) return -1;//由高到低排序 else if(this.y<o.y) return 1; else return 0; //如果x,y都相等,返回0 } } } public class Main { public static int Max = 100000; public static void main(String[] args) { Scanner in = new Scanner(System.in); int N = in.nextInt();//机器的数量 int M = in.nextInt();//任务的数量 int i,j,k; //引用类型数组初始化!!!!动态初始化由系统为数组元素分配默认的初始值:null,即每个数组元素的值都是null。 A[] machine = new A[Max];//机器的工作时间和机器等级 //m数组的Max个数组元素都是引用,而且这个引用并未指向任何有效的内存,因此每个数组元素的值都是null //因为每个数组元素都是null,这相当于定义了Max个连续的A变量,但这个变量还未指向任何有效的内存区,所以这Max个连续的A变量(m数组的数组元素)还不能使用。 for(i=0;i<N;i++){ machine[i] = new A();//!!!!如果没有这一句,对象都没有初始化,因为只创建了数组对象,而数组的每个元素都为null,所以运行的时候会抛出空指针异常。 machine[i].x = in.nextInt(); machine[i].y = in.nextInt(); } A[] task = new A[Max];//任务需要完成的时间和任务难度 for(i=0;i<M;i++){ task[i] = new A(); task[i].x = in.nextInt(); task[i].y = in.nextInt(); } //Arrays.sort(machine);//空指针错误,用Arrays.sort 的排序,必须保证数组里面不存在空值, A m[] = Arrays.copyOfRange(machine,0,N); Arrays.sort(m);//自动调用compareTo //Collections.sort(m);//出现错误!!类型 Collections 中的方法 sort(List<T>)对于参数(A[])不适用 // for(i=0;i<N;i++){ // System.out.println("###"+m[i].x+"###"+m[i].y); // } A t[] = Arrays.copyOfRange(task,0,M); Arrays.sort(t); int mark[] = new int[100];//定义数组,并初始化,默认值就是0 long sum = 0;int count = 0; for(i=0,j=0;i<M;i++){ while(j<N&&t[i].x<=m[j].x){ mark[m[j].y]++; j++; } for(k=t[i].y;k<100;k++){ if(mark[k]!=0){ mark[k]--; count++; sum = sum + 200*t[i].x+3*t[i].y; break; } } } System.out.println(count+" "+sum); } }
解决方案四:
package com.study; import java.util.Scanner; /** * @author ZhaoFang * @date 2018年4月5日 下午9:18:17 * @describe 安排机器:小Q的公司最近接到m个任务,第i个任务需要Xi的时间去完成,难度等级为yi。 * 小Q拥有n台机器,每台机器最长工作时间zi,机器等级wi。 * 对于一个任务,它只能交由一台机器来完成,如果安排给它的机器的最长工作时间小于任务需要的时间,则不能完成, * 如果完成这个任务将获得200*xi + 3*yi收益。 * 对于一台机器,它一天只能完成一个任务,如果它的机器等级小于安排给它的任务难度等级,则不能完成。 * 小Q想在今天尽可能的去完成任务,即完成的任务数量最大。如果有多种安排方案,小Q还想找到收益最大的那个方案。小Q需要你来帮助他计算一下。 * 输入描述:输入包括 N + M + 1行 * 输入的第一行为两个正整数n和m(1 <= n, m <= 100000),表示机器的数量和任务的数量。 * 接下来n行,每行两个整数zi和wi(0 < zi < 1000, 0 <= wi <= 100),表示每台机器的最大工作时间和机器等级。 * 接下来的m行,每行两个整数xi和yi(0 < xi < 1000, 0 <= yi <= 100),表示每个任务需要的完成时间和任务的难度等级。 * 输出描述:输出两个整数,分别表示最大能完成的任务数量和获取的利益。 * 输入: 1 2 * 100 3 * 100 2 * 100 1 * 输出:1 20006 */ public class Tencent3 { public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt();//机器的数量 int m = in.nextInt();//任务的数量 if(n < 1 || n > 100000 || m < 1 || m > 100000) return; int[] z = new int[n];//机器的最大工作时间数组 int[] w = new int[n];//机器等级数组 int[] x = new int[m];//任务需要的完成时间数组 int[] y = new int[m];//任务的难度等级数组 int temp1 = 0; int temp2 = 0; //输入每台机器的最大工作时间和机器等级 for(int i = 0; i < n; i++) { temp1 = in.nextInt(); temp2 = in.nextInt(); if(temp1 > 0 && temp1 < 1000 && temp2 >= 0 && temp2 <= 100) { z[i] = temp1; w[i] = temp2; } } //输入每个任务需要的完成时间和任务的难度等级 for(int j = 0; j < m; j++) { temp1 = in.nextInt(); temp2 = in.nextInt(); if(temp1 > 0 && temp1 < 1000 && temp2 >= 0 && temp2 <= 100) { x[j] = temp1; y[j] = temp2; } } int cost = 0;//获取的收益 int count = 0;//最大能完成的任务数量 int p = -1;//设置标志,如果机器与任务都相匹配,选出收益最大,并保证该任务只被一个机器完成,且一台机器每天只能完成一个任务 int q = -1; //解题难点:存在一个机器适用于多种任务的情况,此时需选出收益最大的那个任务,并将完成的任务数量+1 for(int i = 0; i < n; i++) { for(int j = 0; j < m; j++) { if(z[i] >= x[j] && w[i] >= y[j]) { temp1 = 200*x[j] + 3*y[j]; if(temp1 > cost) { cost = temp1; } if(p != i && q != j) { p = i; q = j; count++; } } } } System.out.println("最大能完成的任务数量为:" + count); System.out.println("获取的利益:" + cost); } }
源码解析:
1. 如何在VS中添加<bits/stdc++.h>
https://blog.csdn.net/dragon60066/article/details/56529077
VS 的include文件夹路径:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.10.25017\include
在vs的include文件夹里面新建一个bits文件夹,里面新建一个名叫stdc++.h的头文件
stdc++.h源文件内容如下:
// C++ includes used for precompiling -*- C++ -*- // Copyright (C) 2003-2015 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // Under Section 7 of GPL version 3, you are granted additional // permissions described in the GCC Runtime Library Exception, version // 3.1, as published by the Free Software Foundation. // You should have received a copy of the GNU General Public License and // a copy of the GCC Runtime Library Exception along with this program; // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // <http://www.gnu.org/licenses/>. /** @file stdc++.h * This is an implementation file for a precompiled header. */ // 17.4.1.2 Headers // C #ifndef _GLIBCXX_NO_ASSERT #include <cassert> #endif #include <cctype> #include <cerrno> #include <cfloat> #include <ciso646> #include <climits> #include <clocale> #include <cmath> #include <csetjmp> #include <csignal> #include <cstdarg> #include <cstddef> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #if __cplusplus >= 201103L #include <ccomplex> #include <cfenv> #include <cinttypes> #include <cstdalign> #include <cstdbool> #include <cstdint> #include <ctgmath> #include <cwchar> #include <cwctype> #endif // C++ #include <algorithm> #include <bitset> #include <complex> #include <deque> #include <exception> #include <fstream> #include <functional> #include <iomanip> #include <ios> #include <iosfwd> #include <iostream> #include <istream> #include <iterator> #include <limits> #include <list> #include <locale> #include <map> #include <memory> #include <new> #include <numeric> #include <ostream> #include <queue> #include <set> #include <sstream> #include <stack> #include <stdexcept> #include <streambuf> #include <string> #include <typeinfo> #include <utility> #include <valarray> #include <vector> #if __cplusplus >= 201103L #include <array> #include <atomic> #include <chrono> #include <condition_variable> #include <forward_list> #include <future> #include <initializer_list> #include <mutex> #include <random> #include <ratio> #include <regex> #include <scoped_allocator> #include <system_error> #include <thread> #include <tuple> #include <typeindex> #include <type_traits> #include <unordered_map> #include <unordered_set> #endif
2. 在国内oj中,poj,hdu 不支持这个函数,这几个oj的编译器问题,其他国外的oj,还有台湾的oj都支持,CF,Topcoder也都支持。
3.
C语言memset()函数:将内存的前n个字节设置为特定的值
头文件:#include <string.h>
memset() 函数用来将指定内存的前n个字节设置为特定的值,其原型为:
void * memset( void * ptr, int value, size_t num );
参数说明:
- ptr 为要操作的内存的指针。
- value 为要设置的值。你既可以向 value 传递 int 类型的值,也可以传递 char 类型的值,int 和 char 可以根据 ASCII 码相互转换。
- num 为 ptr 的前 num 个字节,size_t 就是unsigned int。
【函数说明】memset() 会将 ptr 所指的内存区域的前 num 个字节的值都设置为 value,然后返回指向 ptr 的指针。
memset() 可以将一段内存空间全部设置为特定的值,所以经常用来初始化字符数组。例如:
- char str[20];
- memset(str, '\0', sizeof(str)-1);
【返回值】返回指向 ptr 的指针。
注意:参数 value 虽声明为 int,但必须是 unsigned char,所以范围在0 到255 之间。
范例:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- int main()
- {
- // 不可以声明为 char *str = "http://c.biancheng.net";
- char str[] = "http://c.biancheng.net";
- memset(str, '-', 7);
- puts(str);
- system("pause");
- return EXIT_SUCCESS;
- }
执行结果:
-------c.biancheng.net
注意:字符数组是可以被修改的,字符串是只读的,不能被修改,而 memset() 又必须修改 str,所以不能将 char str[] = "http://c.biancheng.net"; 声明为 char *str = "http://c.biancheng.net";,否则运行时会报错。
4. C++的sort函数
最近在刷ACM经常用到排序,以前老是写冒泡,可把冒泡带到OJ里后发现经常超时,所以本想用快排,可是很多学长推荐用sort函数,因为自己写的快排写不好真的没有sort快,所以毅然决然选择sort函数
用法
1、sort函数可以三个参数也可以两个参数,必须的头文件#include < algorithm>和using namespace std;
2、它使用的排序方法是类似于快排的方法,时间复杂度为n*log2(n)3、Sort函数有三个参数:(第三个参数可不写)
(1)第一个是要排序的数组的起始地址。
(2)第二个是结束的地址(最后一位要排序的地址)
(3)第三个参数是排序的方法,可以是从大到小也可是从小到大,还可以不写第三个参数,此时默认的排序方法是从小到大排序。
两个参数用法
#include <iostream>
#include <algorithm>
int main()
{
int a[20]={2,4,1,23,5,76,0,43,24,65},i;
for(i=0;i<20;i++)
cout<<a[i]<<endl;
sort(a,a+20);
for(i=0;i<20;i++)
cout<<a[i]<<endl;
return 0;
}
三个参数的用法
// sort algorithm example #include <iostream> // std::cout #include <algorithm> // std::sort #include <vector> // std::vector bool myfunction (int i,int j) { return (i<j); }//升序排列 bool myfunction2 (int i,int j) { return (i>j); }//降序排列 struct myclass { bool operator() (int i,int j) { return (i<j);} } myobject; int main () { int myints[8] = {32,71,12,45,26,80,53,33}; std::vector<int> myvector (myints, myints+8); // 32 71 12 45 26 80 53 33 // using default comparison (operator <): std::sort (myvector.begin(), myvector.begin()+4); //(12 32 45 71)26 80 53 33 // using function as comp std::sort (myvector.begin()+4, myvector.end(), myfunction); // 12 32 45 71(26 33 53 80) //std::sort (myints,myints+8,myfunction);不用vector的用法 // using object as comp std::sort (myvector.begin(), myvector.end(), myobject); //(12 26 32 33 45 53 71 80) // print out content: std::cout << "myvector contains:"; for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)//输出 std::cout << ' ' << *it; std::cout << '\n'; return 0; }
string 使用反向迭代器来完成逆序排列
#include <iostream>
using namespace std;
int main()
{
string str("cvicses");
string s(str.rbegin(),str.rend());
cout << s <<endl;
return 0;
}
//输出:sescivc
如果这篇文章帮助到了你,你可以请作者喝一杯咖啡