试题 算法训练 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. 设计模式之GOF23备忘录模式

    备忘录模式Memento 场景: -Word文档编辑时,电脑死机或者断电,再次打开时,word提醒恢复之前的文档 -文件的撤回 核心: -就是保存某个对象内部状态的拷贝,这样以后就可以将该对象恢复到原 ...

  2. [hdu1023]递推

    http://acm.hdu.edu.cn/showproblem.php?pid=1023 如果把栈里面的元素个数表示成状态,每一步(共2 * n步)的状态构成的状态序列的种数就是答案,令dp[i] ...

  3. C++内存管理学习笔记(1)

    /****************************************************************/ /*            学习是合作和分享式的! /* Auth ...

  4. 高通Vuforia(Unity3D)云识别初级使用教程

    高通Vuforia(Unity3D)云识别初级使用教程   最近因项目开发需要,接触了高通的AR引擎Vuforia云识别,个人感觉稳定性还是很不错的,唯一不爽的地方就是免费的云识别库每个月只能识别10 ...

  5. Python基础语法day_02——字符串规则

    day_02 使用方法修改字符串的大小写 将字符串首字母变成大写 >>> name = "ada lovelace" >>> print(nam ...

  6. kali2020解决安装pip的问题

    在以前的版本中,我们需要安装pip时,只需要执行下面命令即可安装: apt-get install python-pip 但是在更新到2020.1以后,上面的命令安装会提示无法定位安装包的问题! 解决 ...

  7. sound of the genuine

    “There is something in every one of you that waits and listens for the sound of the genuine in yours ...

  8. 关于RAID小结

    独立硬盘冗余阵列(RAID, Redundant Array of Independent Disks),旧称廉价磁盘冗余阵列(Redundant Array of Inexpensive Disks ...

  9. Java并发包4--可重入锁ReentrantLock的实现原理

    前言 ReentrantLock是JUC提供的可重入锁的实现,用法上几乎等同于Synchronized,但是ReentrantLock在功能的丰富性上要比Synchronized要强大. 一.Reen ...

  10. Web-Security-Learning

    Web Security sql注入 MySql MySQL False 注入及技巧总结 MySQL 注入攻击与防御 sql注入学习总结 SQL注入防御与绕过的几种姿势 MySQL偏门技巧 mysql ...