洛谷-【图论2-2】最短路3

P1875 佳佳的魔法药水

题目背景

发完了 k 张照片,佳佳却得到了一个坏消息:他的 MM 得病了!佳佳和大家一样焦急万分!治好 MM 的病只有一种办法,那就是传说中的 0 号药水......怎么样才能得到 0 号药水呢?你要知道佳佳的家境也不是很好,成本得足够低才行......

题目描述

得到一种药水有两种方法:可以按照魔法书上的指导自己配置,也可以到魔法商店里去买------那里对于每种药水都有供应,虽然有可能价格很贵。在魔法书上有很多这样的记载:

1 份 A 药水混合 1 份 B 药水就可以得到 1 份 C 药水。(至于为什么 1+1=1,因为......这是魔法世界)好了,现在你知道了需要得到某种药水,还知道所有可能涉及到的药水的价格以及魔法书上所有的配置方法,现在要问的就是:

  1. 最少花多少钱可以配制成功这种珍贵的药水;
  2. 共有多少种不同的花费最少的方案(两种可行的配置方案如果有任何一个步骤不同则视为不同的)。假定初始时你手中并没有任何可以用的药水。

输入格式

第一行有一个整数 N(1≤N≤1000),表示一共涉及到的药水总数。药水从 0∼N−1 顺序编号,0 号药水就是最终要配制的药水。

第二行有 N 个整数,分别表示从 0∼N−1 顺序编号的所有药水在魔法商店的价格(都表示 1 份的价格)。

第三行开始,每行有三个整数 A、B、C,表示 1 份 A 药水混合 1 份 B 药水就可以得到 1 份 C 药水。注意,某两种特定的药水搭配如果能配成新药水的话,那么结果是唯一的。也就是说不会出现某两行的 A、B 相同但 C 不同的情况。

输入以一个空行结束。

输出格式

输出两个用空格隔开的整数,分别表示得到 0 号药水的最小花费以及花费最少的方案的个数。

保证方案数不超过 263−1。

输入输出样例

输入 #1复制

复制代码
7 
10 5 6 3 2 2 3 
1 2 0 
4 5 1 
3 6 2

输出 #1复制

复制代码
10 3

说明/提示

数据范围:

每一种药水的价格均在 [1,2.8×104] 范围内。

样例说明:

最优方案有 3 种,分别是:

直接买 0 号药水;买 4 号药水、5 号药水配制成 1 号药水,直接买 2 号药水,然后配制成 0 号药水;买 4 号药水、5 号药水配制成 1 号药水,买 3 号药水、6 号药水配制成 2 号药水,然后配制成 0 号药水。

实现代码:

cpp 复制代码
#include <cstdio>
#include <iostream>
using namespace std;
int cost[9999],ans[9999];
int soc[3000][3000];
bool f[3000];
int main()
{
    int n;
    
    scanf("%d",&n);
    
    for(int i=1;i<=n;i++)
     scanf("%d",&cost[i]),ans[i]=1;
    int a,b,c; 
    while(scanf("%d%d%d",&a,&b,&c)!=EOF) 
     soc[a+1][b+1]=soc[b+1][a+1]=c+1;
    
    for(int i=1;i<n;i++)
     {
         int maxn=0x7fffffff;
         for(int j=1;j<=n;j++)
          if(!f[j]&&cost[j]<maxn) 
          b=j,maxn=cost[j];
        
        f[b]=1;
        
        for(int j=1;j<=n;j++)
        if(f[j]&&soc[b][j])
         {
             if(cost[b]+cost[j]==cost[soc[b][j]])
              ans[soc[b][j]]+=ans[b]*ans[j];
            if(cost[b]+cost[j]<cost[soc[b][j]]) 
             cost[soc[b][j]]=cost[b]+cost[j],ans[soc[b][j]]=ans[b]*ans[j];
         }
     }
     
     printf("%d %d",cost[1],ans[1]);
     
     return 0;
}

P1462 通往奥格瑞玛的道路

题目背景

在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量。

有一天他醒来后发现自己居然到了联盟的主城暴风城。

在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛。

题目描述

在艾泽拉斯,有 n 个城市。编号为 1,2,3,...,n。

城市之间有 m 条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量。

每次经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。

假设 1 为暴风城,n 为奥格瑞玛,而他的血量最多为 b,出发时他的血量是满的。如果他的血量降低至负数,则他就无法到达奥格瑞玛。

歪嘴哦不希望花很多钱,他想知道,在所有可以到达奥格瑞玛的道路中,对于每条道路所经过的城市单次收费的最大值,其最小值为多少。

输入格式

第一行 3 个正整数,n,m,b。分别表示有 n 个城市,m 条公路,歪嘴哦的血量为 b。

接下来有 n 行,每行 1 个非负整数,fi​。表示经过城市 i,需要交费 fi​ 元。

再接下来有 m 行,每行 3 个正整数,ai​,bi​,ci​(1≤ai​,bi​≤n)。表示城市 ai​ 和城市 bi​ 之间有一条公路,如果从城市 ai​ 到城市 bi​,或者从城市 bi​ 到城市 ai​,会损失 ci​ 的血量。

输出格式

仅一个整数,表示歪嘴哦经过城市单次交费最大值的最小值。

如果他无法到达奥格瑞玛,输出 AFK

输入输出样例

输入 #1复制

复制代码
4 4 8
8
5
6
10
2 1 2
2 4 1
1 3 4
3 4 3

输出 #1复制

复制代码
10

说明/提示

对于 60% 的数据,满足 n≤200,m≤104,b≤200;

对于 100% 的数据,满足 1≤n≤104,1≤m≤5×104,1≤b≤109;

对于 100% 的数据,满足 1≤ci​≤109,0≤fi​≤109,可能有两条边连接着相同的城市。

实现代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define ong long long
const int N=10010;
const int M=100010;
const ong inf=LLONG_MAX/3;
int n,m,b,u,v;
int l,r,mid;
ong wi;
struct node{
	int a;
	ong dis;
};
bool operator < (node x,node y){
	return x.dis>y.dis; 
} priority_queue<node> q;
int top,g[N],f[N];
ong dis[N];
bool vis[N];
struct edge{
	int adj,nex;
	ong w;
}e[M];
void add(int x,int y,ong wor){
	e[++top]=(edge){y,g[x],wor}; 
	g[x]=top;
} void Dijkstra(int maxn){
	for(int i=1;i<=n;i++){
		dis[i]=inf;
		vis[i]=0;
	} dis[1]=0;
	while(!q.empty()) q.pop();
	q.push((node){1,dis[1]});
	while(!q.empty()){
		node now=q.top(); q.pop();
		int x=now.a;
		if(vis[x]) continue;
		vis[x]=1;
		for(int i=g[x];i;i=e[i].nex){
			int p=e[i].adj;
			if(f[p]>maxn) continue;
			if(dis[x]+e[i].w<dis[p]){
				dis[p]=dis[x]+e[i].w;
				q.push((node){p,dis[p]});
			}
		}
	}
} int main(){
	scanf("%d%d%d",&n,&m,&b);
	for(int i=1;i<=n;i++){
		scanf("%d",f+i);
		r=max(r,f[i]);
	} l=max(f[1],f[n]);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&u,&v,&wi);
		add(u,v,wi);
		add(v,u,wi);
	} while(l<r){
		mid=(l+r)>>1;
		Dijkstra(mid);
		if(dis[n]>b)
			l=mid+1;
		else r=mid;
	} Dijkstra(l);
	if(dis[n]>b) printf("AFK\n");
	else printf("%d\n",l);
	return 0;
} 

P1073 [NOIP 2009 提高组] 最优贸易

题目背景

本题原题数据极弱,Subtask 0 中的测试点为原题测试点,Subtask 1 中的测试点为 Hack 数据。

题目描述

C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市。任意两个城市之间最多只有一条道路直接相连。这 m 条道路中有一部分为单向通行的道路,一部分为双向通行的道路,双向通行的道路在统计条数时也计为 1 条。

C 国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价格不一定相同。但是,同一种商品在同一个城市的买入价和卖出价始终是相同的。

商人阿龙来到 C 国旅游。当他得知同一种商品在不同城市的价格可能会不同这一信息之后,便决定在旅游的同时,利用商品在不同城市中的差价赚回一点旅费。设 C 国 n 个城市的标号从 1∼n,阿龙决定从 1 号城市出发,并最终在 n 号城市结束自己的旅行。在旅游的过程中,任何城市可以重复经过多次,但不要求经过所有 n 个城市。阿龙通过这样的贸易方式赚取旅费:他会选择一个经过的城市买入他最喜欢的商品――水晶球,并在之后经过的另一个城市卖出这个水晶球,用赚取的差价当做旅费。由于阿龙主要是来 C 国旅游,他决定这个贸易只进行最多一次,当然,在赚不到差价的情况下他就无需进行贸易。

假设 C 国有 5 个大城市,城市的编号和道路连接情况如下图,单向箭头表示这条道路为单向通行,双向箭头表示这条道路为双向通行。

假设 1∼n 号城市的水晶球价格分别为 4,3,5,6,1。

阿龙可以选择如下一条线路:1→2→3→5,并在 2 号城市以 3 的价格买入水晶球,在 3 号城市以 5 的价格卖出水晶球,赚取的旅费数为 2。

阿龙也可以选择如下一条线路:1→4→5→4→5,并在第 1 次到达 5 号城市时以 1 的价格买入水晶球,在第 2 次到达 4 号城市时以 6 的价格卖出水晶球,赚取的旅费数为 5。

现在给出 n 个城市的水晶球价格,m 条道路的信息(每条道路所连接的两个城市的编号以及该条道路的通行情况)。请你告诉阿龙,他最多能赚取多少旅费。

输入格式

第一行包含 2 个正整数 n 和 m,中间用一个空格隔开,分别表示城市的数目和道路的数目。

第二行 n 个正整数,每两个整数之间用一个空格隔开,按标号顺序分别表示这 n 个城市的商品价格。

接下来 m 行,每行有 3 个正整数 x,y,z,每两个整数之间用一个空格隔开。如果 z=1,表示这条道路是城市 x 到城市 y 的单向道路;如果 z=2,表示这条道路为城市 x 和城市 y 之间的双向道路。

输出格式

一个整数,表示最多能赚取的旅费。如果没有进行贸易,则输出 0。

输入输出样例

输入 #1复制

复制代码
5 5 
4 3 5 6 1 
1 2 1 
1 4 1 
2 3 2 
3 5 1 
4 5 2 

输出 #1复制

复制代码
5

说明/提示

【数据范围】

输入数据保证 1 号城市可以到达 n 号城市。

对于 10% 的数据,1≤n≤6。

对于 30% 的数据,1≤n≤100。

对于 50% 的数据,不存在一条旅游路线,可以从一个城市出发,再回到这个城市。

对于 100% 的数据,1≤n≤100000,1≤m≤500000,1≤x,y≤n,1≤z≤2,1≤ 各城市的编号 ≤n。

水晶球价格 ≤100。

NOIP 2009 提高组 第三题

实现代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;

int n, m, d[maxn*3], inq[maxn*3];
vector<pair<int, int>> G[maxn*3];

#define t(x,i) (x+i*n)
#define add(x, y) G[t(x,0)].push_back({t(y,0), 0}), G[t(x,1)].push_back({t(y,1),0}), G[t(x,2)].push_back({t(y,2),0})

void spfa(int s) {
    for(int i = 1;i <= n*3;i++) d[i] = INT_MIN; 
    d[s] = 0; 
    queue<int> Q; inq[s] = true; Q.push(s);
    while(!Q.empty()) {
        int x = Q.front(); Q.pop(); inq[x] = false;
        for(auto [v, len] : G[x]) 
            if(d[v] < d[x] + len) {
                d[v] = d[x] + len;
                if(!inq[v]) { Q.push(v); inq[v] = true; }
            } 
    }
}

int main() {
    ios_base::sync_with_stdio(0); cin.tie(0); 
    cin >> n >> m;
    for(int i = 1, v;i <= n; ++i) {
        cin >> v;
        G[t(i,0)].push_back({t(i,1), -v});
        G[t(i,1)].push_back({t(i,2), v});
    }
    for(int i = 1,x,y,z;i <= m; ++i) {
        cin >> x >> y >> z; add(x, y);
        if(z == 2) add(y, x);
    }
    spfa(t(1,0));
    cout << d[t(n,2)] << endl;
    return 0;
}
相关推荐
那个失眠的夜7 小时前
SpringBoot
java·开发语言·spring boot·spring·mvc·mybatis
yong99907 小时前
基于VC++的图像匹配金字塔算法
c++·算法·计算机视觉
范范@7 小时前
python基础-5大容器
开发语言·python
会编程的土豆7 小时前
Go 连接 Redis 代码详细解析
开发语言·redis·golang
Rhi6377 小时前
第 4 篇:用JWT与角色权限构筑安全的API防线
算法
测试员周周7 小时前
【AI测试路线图2】功能测试转 AI 测试:4~5 个月,一条最稳的路
开发语言·人工智能·python·功能测试·测试工具·单元测试·pytest
fengfuyao9858 小时前
基于MATLAB的ALOHA防碰撞、二进制搜索算法和帧时隙算法
人工智能·算法·matlab
多敲代码防脱发8 小时前
Spring进阶(Bean的生命周期与Bean的后处理器)
java·服务器·开发语言·spring boot·spring·servlet
yongui478348 小时前
光伏逆变器完整控制程序
算法