试题 算法训练 Remember the A La Mode

问题描述

  Hugh Samston经营着一个为今年的ICPC世界总决赛的参与者提供甜点的餐饮服务。他将会提供上面有冰激凌的饼片。为了满足不同的需求,他准备了许多不同的饼片和冰激凌。

  Hugh希望以一份饼片上一份冰激凌的方式来提供甜点。然而,作为一个商人,他希望能赚到尽可能多的钱。他知道不同种类的饼片和冰激凌组合的价格,也知道那些冰激凌和那些饼片不能组合在一起。

  Hugh想根据每种饼片和冰激凌的数量,以及之前提到的不同组合的情况,确定他能获得的利润的范围。

输入格式

  测试数据的输入一定会满足的格式。

  输入的第一行包含两个整数P, I,分别表示饼片和冰激凌的种类数。

  接下来一行包含P个整数,表示每种类型饼片的数量。

  接下来一行包含I个整数,表示每种类型冰激凌的数量。

  接下来P行,每行包含I个实数,表示每种类型饼片和冰激凌组合的结果。

  如果这种饼片和这种冰激凌可以组合,则为一个(0,10)的实数,表示这种组合的收益。

  否则,则为-1,表示这两种之间不能组合。

输出格式

  输出一行,以"(最小收益) to (最大收益)"的方式输出利润的范围。

请注意:所有的饼片和冰激凌都必须用完。

样例输入

2 3

40 50

27 30 33

1.11 1.27 0.70

-1 2 0.34

样例输出

91.70 to 105.87

数据规模和约定

  0 < P,I <= 50,每种类型饼片或冰激凌数量不超过100。

PS:

这个题给我晕坏了,我的天,这半天就肝了这么几道题,躺了,浑身晕


import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner; public class Main {
static int[] PArray, IArray, pre, dis; /*分别用来保存P和I的数量,pre和dis用作SPFA算法中保存前节点和点到源点的距离*/ static int[][] Weight; /* 保存权重 */ static List<List<Integer>> index; /* index[i]表示所有从i出发的边的集合 */ static int minCost = 0, maxCost = 0, P, I,count = -1; static List<Edge> E; /* 保存图中所有边 */ public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
P = sc.nextInt();
I = sc.nextInt();
PArray = new int[P];
IArray = new int[I];
pre = new int[P + I + 2];
dis = new int[P + I + 2];
Weight = new int[P + I + 2][P + I + 2];
index = new ArrayList<List<Integer>>();
E = new ArrayList<Edge>();
sc.nextLine(); for (int i = 0; i < P + I + 2; i++)
{
index.add(new ArrayList<Integer>());
}
for (int i = 0; i < P; i++)
{
PArray[i] = sc.nextInt();
}
sc.nextLine();
for (int i = 0; i < I; i++)
{
IArray[i] = sc.nextInt();
}
sc.nextLine();
for (int i = 1; i <= P; i++)
{
for (int j = P + 1; j <= I + P; j++)
{
BigDecimal in = new BigDecimal(Double.toString(sc.nextDouble()));
in = in.multiply(new BigDecimal(100));
String toStr = in.toString();
int num = Integer.parseInt(toStr.substring(0, toStr.indexOf('.')));
Weight[i][j] = num;
if (num != -100)
{
add(i, j, Math.min(PArray[i - 1], IArray[j - P - 1]), 0, -num);
add(j, i, 0, 0, num);
/* 同时构造边和反向边,正向边的权重先取反,来求最大花费 */
}
}
sc.nextLine();
}
for (int i = 1; i <= P; i++)
{
add(0, i, PArray[i - 1], 0, 0);
add(i, 0, 0, 0, 0);
/* 构造超级源点的边以及反向边 */
} for (int i = P + 1; i <= P + I; i++)
{
add(i, P + I + 1, IArray[i - P - 1], 0, 0);
add(P + I + 1, i, 0, 0, 0);
/* 构造超级汇点的边以及反向边 */
}
MCMF(0, P + I + 1);
maxCost = -minCost;
E.clear();
minCost = 0; /* 重新按照weight数组保存的权重值构造Edge集合,来计算最小收益
* 事先已经构造好index集合,这次可以直接向E中add
*/
for (int i = 1; i <= P; i++)
{
for (int j = P + 1; j <= I + P; j++)
{
if (Weight[i][j] != -100)
{
E.add(new Edge(i, j, Math.min(PArray[i - 1], IArray[j - P - 1]), 0, Weight[i][j]));
E.add(new Edge(j, i, 0, 0, -Weight[i][j]));
}
}
}
for (int i = 1; i <= P; i++)
{
E.add(new Edge(0, i, PArray[i - 1], 0, 0));
E.add(new Edge(i, 0, 0, 0, 0));
} for (int i = P + 1; i <= P + I; i++)
{
E.add(new Edge(i, P + I + 1, IArray[i - P - 1], 0, 0));
E.add(new Edge(P + I + 1, i, 0, 0, 0));
}
MCMF(0, I + P + 1);
System.out.format("%.2f to %.2f", minCost / 100.0, maxCost / 100.0);
} public static void add(int from, int to, int cap, int flow, int weight)
{
/* 构造并保存边时,同时填写index */
E.add(new Edge(from, to, cap, flow, weight));
count++;
index.get(from).add(count);
} public static Edge getByNum(int from, int to, List<Edge> E)
{
/* 通过起点和终点确定边 */
for (int i : index.get(from))
{
if (E.get(i).to == to)
{
return E.get(i);
}
}
return null;
} public static void MCMF(int s, int n)
{
while (SPFA(s, n))
{
int now = n, minFlow = Integer.MAX_VALUE;
while (now != s)
{
/* 算出增广路径上每条边上能允许多出的最大流 */
minFlow = Math.min(minFlow, getByNum(pre[now], now, E).cap);
now = pre[now];
}
now = n;
minCost += minFlow * dis[n];
while (now != s)
{
/* 增广路径上每条边的容量减少minFlow, 反向路径则增加minFlow */
getByNum(pre[now], now, E).cap -= minFlow;
getByNum(now, pre[now], E).cap += minFlow;
now = pre[now];
}
}
} public static boolean SPFA(int s, int n)
{
/* 寻找s-n增广路径, 并用pre保存这条路径上每个节点的前节点 */
Queue<Integer> Q = new LinkedList<Integer>();
for (int i = 0; i < dis.length; i++)
{
dis[i] = Integer.MAX_VALUE;
pre[i] = -1;
}
int[] count = new int[102];
Q.add(s);
dis[s] = 0;
pre[s] = -1;
count[s]++;
while (!Q.isEmpty())
{
int from = Q.poll();
for (int i : index.get(from))
{
if (E.get(i).cap > 0)
{
Edge e = E.get(i);
int to = e.to;
if (dis[to] > dis[from] + e.weight)
{
/* relax操作 */
dis[to] = dis[from] + e.weight;
pre[to] = from;
if (!Q.contains(to))
{
Q.add(to);
count[to]++;
if (count[to] > n)
{
return false;
}
}
}
}
}
}
return !(pre[n] == -1);
/* 单纯写成 return true 则在pre数组全是-1的情况下也会return true */
} } class Edge
{
int from, to, cap, flow, weight; public Edge(int f, int t, int c, int fl, int w)
{
this.from = f;
this.to = t;
this.cap = c;
this.flow = fl;
this.weight = w;
}
}

Java实现 蓝桥杯 算法训练 Remember the A La Mode(暴力)的更多相关文章

  1. Java实现 蓝桥杯 算法训练 猴子吃包子(暴力)

    试题 算法训练 猴子吃包子 问题描述 从前,有一只吃包子很厉害的猴子,它可以吃无数个包子,但是,它吃不同的包子速度也不同:肉包每秒钟吃x个:韭菜包每秒钟吃y个:没有馅的包子每秒钟吃z个:现在有x1个肉 ...

  2. Java实现蓝桥杯 算法训练 大等于n的最小完全平方数

    试题 算法训练 大等于n的最小完全平方数 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 输出大等于n的最小的完全平方数. 若一个数能表示成某个自然数的平方的形式,则称这个数为完全平 ...

  3. java实现 蓝桥杯 算法训练 Password Suspects

    问题描述 在年轻的时候,我们故事中的英雄--国王 Copa--他的私人数据并不是完全安全地隐蔽.对他来说是,这不可接受的.因此,他发明了一种密码,好记又难以破解.后来,他才知道这种密码是一个长度为奇数 ...

  4. Java实现 蓝桥杯 算法训练VIP 报数(暴力+数学)约瑟夫环问题

    试题 算法训练 报数 问题描述 现有n个同学站成一圈,顺时针编号1至n.从1号同学开始顺时针1/2报数,报到1的同学留在原地,报到2的同学退出圆圈,直到只剩一名同学为止.问最后剩下的同学编号. 输入格 ...

  5. Java实现蓝桥杯 算法训练 ALGO-15 旅行家的预算

    问题描述 一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的).给定两个城市之间的距离D1.汽车油箱的容量C(以升为单位).每升汽油能行驶的距离D2.出发点每升汽油价格P和沿 ...

  6. Java实现 蓝桥杯 算法训练 审美课

    算法训练 审美课 时间限制:1.0s 内存限制:256.0MB 提交此题 问题描述 <审美的历程>课上有n位学生,帅老师展示了m幅画,其中有些是梵高的作品,另外的都出自五岁小朋友之手.老师 ...

  7. Java实现 蓝桥杯 算法训练 多阶乘计算

    试题 算法训练 多阶乘计算 问题描述 我们知道,阶乘n!表示n*(n-1)(n-2)-21, 类似的,可以定义多阶乘计算,例如:5!!=531,依次可以有n!..!(k个'!',可以简单表示为n(k) ...

  8. Java实现 蓝桥杯 算法训练 找零钱

    试题 算法训练 找零钱 问题描述 有n个人正在饭堂排队买海北鸡饭.每份海北鸡饭要25元.奇怪的是,每个人手里只有一张钞票(每张钞票的面值为25.50.100元),而且饭堂阿姨一开始没有任何零钱.请问饭 ...

  9. Java实现 蓝桥杯 算法训练 第五次作业:字符串排序

    试题 算法训练 第五次作业:字符串排序 问题描述 输入一个小写字符串,按从小到大的顺序输出. 输入格式 bcaed 输出格式 abcde 顶格输出,中间没有空格 样例输入 一个满足题目要求的输入范例. ...

随机推荐

  1. 【HBase】协处理器是什么?又能干什么?怎么用?

    目录 简单了解 官方帮助文档 协处理器出现的原因 协处理器的分类 Observer Endpoint Phoenix 协处理器的使用 加载方式 静态加载 动态加载 协处理器的卸载 协处理器Observ ...

  2. 【Kafka】Kafka简单介绍

    目录 基本介绍 概述 优点 主要应用场景 Kafka的架构 四大核心API 架构内部细节 基本介绍 概述 Kafka官网网站:http://kafka.apache.org/ Kafka是由Apach ...

  3. Android Bluetooth How To--Based on Android L Bluedroid

    Android Bluetooth How To(Based on Android L Bluedroid) 持续更新中… 1.How to enable btsnoop log? a) UI Set ...

  4. uCOS2014.1.10

    uC/OS-Ⅱ任务的结构有两种:一种是无限循环结构:另一种是只执行一次的程序结构.若采用只执行一次的程序结构,就要用任务删除函数来实现. uC/OS-Ⅱ进行任务的管理是从调用启动函数OSStart() ...

  5. 解决anaconda与pycharm冲突导致import无法使用

    解决annacode与python冲突: 一.File->Setting-> 点击Add-> 然后就完美解决 二.记得重启,检查创建的项目是右键python package-> ...

  6. HMM-维特比算法理解与实现(python)

    HMM-前向后向算法理解与实现(python) HMM-维特比算法理解与实现(python) 解码问题 给定观测序列 \(O=O_1O_2...O_T\),模型 \(\lambda (A,B,\pi) ...

  7. 这份书单会告诉你,Java网络编程其实很重要

  8. Winform GDI+ 绘图一:绘制2D电池

    winform桌面软件开发,在工业控制领域的使用还是很广泛的,打算好好学习一下GDI+绘图.以前都是用别人的轮子,自己也打算封装一些工业控制领域常用的控件. 今天要将的是,利用缓动函数动态绘制电池. ...

  9. Springboot 上传CSV文件并将数据存入数据库

    .xml文件依赖配置 <!--csv依赖 --> <dependency> <groupId>org.apache.commons</groupId> ...

  10. python3.x 基础三:文件IO

    打开文件的两种方式 1.直接打开文件并赋值给变量,打开后得到操作句柄,但不会自动关闭 file = open('文件名‘,'打开模式',’编码‘) fd = open('../config/file1 ...