Java实现 蓝桥杯 算法训练 Remember the A La Mode(暴力)
试题 算法训练 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(暴力)的更多相关文章
- Java实现 蓝桥杯 算法训练 猴子吃包子(暴力)
		
试题 算法训练 猴子吃包子 问题描述 从前,有一只吃包子很厉害的猴子,它可以吃无数个包子,但是,它吃不同的包子速度也不同:肉包每秒钟吃x个:韭菜包每秒钟吃y个:没有馅的包子每秒钟吃z个:现在有x1个肉 ...
 - Java实现蓝桥杯 算法训练 大等于n的最小完全平方数
		
试题 算法训练 大等于n的最小完全平方数 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 输出大等于n的最小的完全平方数. 若一个数能表示成某个自然数的平方的形式,则称这个数为完全平 ...
 - java实现 蓝桥杯 算法训练 Password Suspects
		
问题描述 在年轻的时候,我们故事中的英雄--国王 Copa--他的私人数据并不是完全安全地隐蔽.对他来说是,这不可接受的.因此,他发明了一种密码,好记又难以破解.后来,他才知道这种密码是一个长度为奇数 ...
 - Java实现 蓝桥杯 算法训练VIP  报数(暴力+数学)约瑟夫环问题
		
试题 算法训练 报数 问题描述 现有n个同学站成一圈,顺时针编号1至n.从1号同学开始顺时针1/2报数,报到1的同学留在原地,报到2的同学退出圆圈,直到只剩一名同学为止.问最后剩下的同学编号. 输入格 ...
 - Java实现蓝桥杯 算法训练 ALGO-15 旅行家的预算
		
问题描述 一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的).给定两个城市之间的距离D1.汽车油箱的容量C(以升为单位).每升汽油能行驶的距离D2.出发点每升汽油价格P和沿 ...
 - Java实现 蓝桥杯 算法训练 审美课
		
算法训练 审美课 时间限制:1.0s 内存限制:256.0MB 提交此题 问题描述 <审美的历程>课上有n位学生,帅老师展示了m幅画,其中有些是梵高的作品,另外的都出自五岁小朋友之手.老师 ...
 - Java实现 蓝桥杯 算法训练   多阶乘计算
		
试题 算法训练 多阶乘计算 问题描述 我们知道,阶乘n!表示n*(n-1)(n-2)-21, 类似的,可以定义多阶乘计算,例如:5!!=531,依次可以有n!..!(k个'!',可以简单表示为n(k) ...
 - Java实现 蓝桥杯 算法训练 找零钱
		
试题 算法训练 找零钱 问题描述 有n个人正在饭堂排队买海北鸡饭.每份海北鸡饭要25元.奇怪的是,每个人手里只有一张钞票(每张钞票的面值为25.50.100元),而且饭堂阿姨一开始没有任何零钱.请问饭 ...
 - Java实现 蓝桥杯 算法训练 第五次作业:字符串排序
		
试题 算法训练 第五次作业:字符串排序 问题描述 输入一个小写字符串,按从小到大的顺序输出. 输入格式 bcaed 输出格式 abcde 顶格输出,中间没有空格 样例输入 一个满足题目要求的输入范例. ...
 
随机推荐
- learn from collection framework design
			
最难忍受的痛苦,也许是想干一件事情而又不去干.--罗曼·罗兰 前言 本篇文章算是拾人牙慧吧,偶尔谷歌到一个能很好把collection framework design讲好的文档,一是为了总结提升,也 ...
 - Openwrt:mtd/mtd_write烧写固件
			
文章目录 1 查看当前系统分区信息 2 备份固件firmware 3 恢复固件firmware 4 备份恢复Openwrt路由器配置 5 恢复Openwrt路由器默认设置 6 刷新路由器固件 比较简单 ...
 - [hdu4123]dfs区间化+RMQ
			
题意:给一个树编号0~n-1,一个数组a[i]为节点i在树上走的最大距离(不重复点),然后求最大的区间,使得区间最大差异小于某个值.dfs求出每个数组,同时区间化.枚举区间左边界,右边界同样递增,类似 ...
 - 1005 Spell It Right (20分)
			
1005 Spell It Right (20分) 题目: Given a non-negative integer N, your task is to compute the sum of all ...
 - Fragment 嵌套Fragment注意事项
			
最近项目新功能需要在垂直方方向可以循环滚动,并且水平方向也可以水平循环滚动,并且可以定位到指定item上.很自然的想到了ViewPager和 VerticalViewPager来解决项目需求,UI的大 ...
 - 2018-06-28  jq CSS处理
			
CSS处理 1.CSS样式 css() -> 获取jq对象的css样式 css({'':"'}) ->设置jq对象的css样式 相当于js对象的style()方法 2.位置 of ...
 - phantomJS安装出错解决办法
			
解决办法:https://github.com/xhlwill/blog/issues/11
 - sh: react-scripts: command not found after running npm start
			
今天遇到一堆bug,从早上10点到现在8成的时间都像是浪费了..... https://stackoverflow.com/questions/40546231/sh-react-scripts-co ...
 - MySQL慢查询优化(线上案例调优)
			
文章说明 这篇文章主要是记录自己最近在真实工作中遇到的慢查询的案例,然后进行调优分析的过程,欢迎大家一起讨论调优经验.(以下出现的表名,列名都是化名,实际数据也进行过一点微调.) PS:最近做了一个面 ...
 - 【c#】Visual Studio 的下载及安装
			
“工欲善其事,必先利其器” 这篇博文我们介绍一下如何正确的安装基于c#使用的vs 2017. 1.首先在官网下载Visual Studio,下载地址:https://www.visualstudio. ...