最短路习题(二)

6.成仙之路

有个蘑菇精想要成仙,但是他必须要收集10000个精灵宝石,不过他要是有花精灵的泪水,就只要8000个精灵宝石就可以了,或者如果他有花精灵的血滴,就只要5000个精灵宝石便可以成仙了。蘑菇精可以和森林里的其他精灵交换东西,但是修为等级差距过大的交换会影响修炼蘑菇精就跑到花精灵那里,向他索要泪水或血滴,花精灵要他用精灵宝石来换,或者替他弄来其他的东西,他可以降低价格。蘑菇精于是又跑到其他地方,其他精灵也提出了类似的要求,或者直接用精灵宝石换,或者找到其他东西就可以降低价格。不过蘑菇精没必要用多样东西去换一样东西,因为这不会得到更低的价格。蘑菇精现在很需要你的帮忙,让他用最少的精灵宝石帮助他成仙。另外他要告诉你的是,在这 个森林里,交换东西,修为差距超过一定限制的两个精灵之间不会进行任何形式的直接接触,包括交易,否则会影响修炼。蘑菇精是外来精灵,所以可以不受这些限制。但是如果他和某个修为等级较低的精灵进行了交易,修为等级较高的的精灵有可能不会再和他交易,他们认为这样等于是间接接触,反过来也一样。因此你需要在考虑所有的情况以后给他提供一个最好的方案。 
为了方便起见,我们把所有的物品从开始进行编号,成仙也看作一个物品,并且编号总是1。每个物品都有对应的代价 P,主人精灵的修为等级L ,以及一系列的替代品Ti和该替代品所对应的“优惠”Vi 。如果两个精灵修为等级差距超过了M ,就不能“间接交易”。你必须根据这些数据来计算出蘑菇精最少需要多少精灵宝石才能成仙。 
输入格式
第一行是两个整数 ,依次表示修为等级差距限制和M,N(1< =M< =20,1< =N< =20000)物品的总数。接下来按照编号从小到大依次给出了N个物品的描述。每个物品的描述开头是P,L,X三个非负整数 ( X< N),依次表示该物品的代价、主人精灵的修为等级和替代品总数。接下来X 行每行包括两个整数T 和V ,分别表示替代品的编号和“优惠价格”。(Σx< =200000) 
输出格式 
对于每个测试数据,在单独一行内输出最少需要的精灵宝石数。 
样例输入 
1 4 
10000 3 2 
2 8000 
3 5000 
1000 2 1 
4 200 
3000 2 1 
4 200 
50 2 0 
样例输出 
5250

新建一个点0,表示什么都还没有,也就是起点,每一个物品作为一个点,到了这个点表示我当前手上拿的就是这个物品,0向其它的点连边,边权为物品本身的价值,表示我可以直接购买,可以替换的就连有向边,边权为替换的价钱,最后所求的就是从0到1的最短路。 就是成仙的最短路

代码如下:


import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {

	static int n, m, d, INF = Integer.MAX_VALUE, ans = INF;
	static int[] l;// 主人精灵的修为等级
	static int[] dis;
	static boolean[] vis;
	static LinkedList<Point9>[] list;

	static void init() {
		l = new int[n + 1];
		dis = new int[n + 1];
		vis = new boolean[n + 1];
		list = new LinkedList[n + 1];
		for (int i = 0; i <= n; i++) {
			list[i] = new LinkedList<Point9>();
		}
	}

	// 判断等级差距
	static boolean judge(int x) {
		if (l[x] > d + m || l[x] < d)
			return false;
		return true;
	}

	// spfa判断最短路
	static void spfa() {
		Arrays.fill(dis, INF);
		dis[0]=0;
		Queue<Integer> q = new LinkedList<>();
		q.offer(0);
		vis[0] = true;
		int u = 0;
		while (!q.isEmpty()) {
			u = q.poll();
			vis[u] = false;

			for (int j = 0; j < list[u].size(); j++) {
				int v = list[u].get(j).v;
				int w = list[u].get(j).w;
				if (dis[v] > dis[u] + w && judge(v)) {
					dis[v] = dis[u] + w;
					if (!vis[v]) {
						q.offer(v);
						vis[v] = true;
					}
				}
			}
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Scanner sc = new Scanner(System.in);
		m = sc.nextInt();
		n = sc.nextInt();
		init();
		int p1, k, num, p2;
		for (int i = 1; i <= n; i++) {
			p1 = sc.nextInt();// 换取该物品的代价
			l[i] = sc.nextInt();// 主人精灵修为
			k = sc.nextInt();// 替代品总数
			list[0].add(new Point9(i, p1));
			for (int j = 1; j <= k; j++) {
				num = sc.nextInt();// 物品编号
				p2 = sc.nextInt();// 该物品可以替换的价格
				list[num].add(new Point9(i, p2));
			}
		}
		for (d = l[1] - m; d <= l[1] + m; d++) {// 开始和第一个精灵交易时,等级差距确定一下,d为最低等级
			spfa();
			ans = Math.min(ans, dis[1]);
		}
		System.out.println(ans);

	}

}

class Point9 {
	int v, w;

	public Point9(int v, int w) {
		this.v = v;
		this.w = w;
	}
}

7.蒜厂年会

 输入数据:

4 2
3 1 2 3
2 3 4

输出数据:

100

floyd模板题:

代码如下:


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class Main {

	static int n, m;
	static int[][] g;

	static void init() {
		g = new int[n + 1][n + 1];
		for (int i = 0; i < n + 1; i++)
			for(int j=0;j<n+1;j++)
				g[i][j]=(int) 1e9;
	}

	static void floyd() {
		for (int k = 1; k <= n; k++) {
			for (int i = 1; i <= n; i++) {
				for (int j = 1; j <= n; j++) {
					g[i][j] = Math.min(g[i][j], g[i][k] + g[k][j]);
				}
			}
		}

	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Scanner sc = new Scanner(System.in);
		
		n = sc.nextInt();// n名员工
		m = sc.nextInt();// m个项目
		init();
		for (int i = 1; i <= m; i++) {
			int k = sc.nextInt();// 项目参与人数
			ArrayList<Integer> list = new ArrayList<>();
			while (k-- > 0) {
				int e = sc.nextInt();// 员工编号
				list.add(e);
			}
			for (int j = 0; j < list.size(); j++) {
				for (int s = 0; s < list.size(); s++) {
					int x = list.get(j);
					int y = list.get(s);
					g[x][y] = 1;
				}
			}

		}
		floyd();
		int ans = Integer.MAX_VALUE;
		for(int i=1;i<=n;i++) {
			int sum=0;
			for(int j=1;j<=n;j++) {
				if(i==j)continue;
				sum+=g[i][j];
			}
			ans=Math.min(ans, sum);
		}
		ans=ans*100/(n-1);
		System.out.println(ans);
	}

}

 8.蒜头君的训练室

问题描述

蒜头君的训练室有 N 个站点,另外有 M 条单向边连接这些站点。第 i 条路从 Si站到 Ei站,有高度为 Hi的围栏,蒜头君是需要跳跃的。 
现在蒜头君们有 T 个任务要完成。第 ii 个任务,蒜头君要从 Ai站到 Bi站,蒜头君想要他们路径中最高围栏尽可能小。请你确定这个高度。 
输入格式 
第一行输入三个整数 N, M, T。(1≤N≤300,1≤M≤25000,1≤T≤40000)。 
接下来 M 行,每行三个整数 Si,Ei,Hi(1≤Si,Ei≤N,1≤Hi≤10e6) 
再接下来 T 行,每行两个整数 Ai,Bi。(1≤Ai,Bi≤N) 
除了这 M 组关系,其他任意两人之间均不相识。 
输出格式 
对于每个询问,输出最小的最大高度。若无法到达,则输出−1。 
样例输入 
5 6 3 
1 2 12 
3 2 8 
1 3 5 
2 5 3 
3 4 4 
2 4 8 
3 4 
1 2 
5 1 
样例输出 


-1

floyd算法,需要注意下 “蒜头君想要他们路径中最高围栏尽可能小”

代码如下:


import java.util.Scanner;

public class Main {

	static int n, m, t, INF = 10000000;
	static int[][] g;

	static void init() {
		g = new int[n + 1][n + 1];
		for (int i = 0; i <= n; i++) {
			for (int j = 0; j <= n; j++)
				g[i][j] = INF;
		}
	}

	static void floyd() {
		for (int k = 1; k <= n; k++) {
			for (int i = 1; i <= n; i++) {
				for (int j = 1; j <= n; j++) {
					g[i][j] = Math.min(Math.max(g[i][k], g[k][j]), g[i][j]);
				}
			}
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		m = sc.nextInt();
		t = sc.nextInt();
		init();
		for (int i = 1; i <= m; i++) {
			int s = sc.nextInt();
			int e = sc.nextInt();
			int h = sc.nextInt();
			g[s][e] = h;
		}
		floyd();
		for (int i = 1; i <= t; i++) {
			int a = sc.nextInt();
			int b = sc.nextInt();
			if (g[a][b] == INF) {
				System.out.println(-1);
			} else {
				System.out.println(g[a][b]);
			}
		}
	}

}

9.美好的邂逅

蒜头君走在校园里,邂逅了一个美女,可是蒜头君胆怯了,并没有上前搭讪。回到宿舍的蒜头君越想越难过,好在室友提出了一个很好的办法,可以通过同学的同学的同学这样的关系,当同学的同学这样的关系叠加到足够大的时候,覆盖的人群也就会足够多,这样就能找到这个美女了,而且蒜头君的室友很肯定的说,最多隔 66 个人,就一定能找到这个美女,蒜头君有点不相信了,想验证一下室友的想法,他和室友一起对 NN 个人展开了调查,得到了他们之间的相识关系,现在请你编写一个程序判断一下,是不是这 NN 个人当中的每个人最多通过六个人就能找到其他任意一个人。

输入格式

第一行包含两个整数 N,M (0<N<100, 0<M<200N,M(0<N<100,0<M<200),分别代表蒜头君和他的室友统计的人数(这些人分别编成 11 ~ NN 号),以及他们之间的关系数。

接下来有 MM 行,每行两个整数 A, B(1\leq A,B \le NA,B(1≤A,B≤N)表示编号为 AA 和编号 BB 的人互相认识。

除了这 MM 组关系,其他任意两人之间均不相识。

输出格式

如果数据能满足室友提出的猜想,那么就在一行里输出Yes,否则输出No。

输入数据:

8 7
1 2
2 3
3 4
4 5
5 6
6 7
7 8

输出数据:

Yes

代码如下:


import java.util.Scanner;

public class Main {

	static int n, m;
	static int[][] g;

	static void init() {
		g = new int[n + 1][n + 1];
		for (int i = 0; i < n + 1; i++) {
			for (int j = 0; j < n + 1; j++) {
				g[i][j] = 100000;
			}
		}
	}

	static void floyd() {
		for (int k = 1; k <= n; k++) {
			for (int i = 1; i <= n; i++) {
				for (int j = 1; j <= n; j++) {
					g[i][j] = Math.min(g[i][j], g[i][k] + g[k][j]);
				}
			}
		}
	}

	static boolean check() {
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				if (g[i][j] > 7)
					return false;
			}
		}
		return true;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		m = sc.nextInt();
		init();
		for (int i = 1; i <= m; i++) {
			int a = sc.nextInt();
			int b = sc.nextInt();
			g[a][b] = g[b][a] = 1;
		}
		floyd();
		boolean f = check();
		if (f) {
			System.out.println("Yes");
		} else {
			System.out.println("No");
		}
	}

}
发布了133 篇原创文章 · 获赞 31 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_41921315/article/details/89364027