PAT A1003 Emergency

PAT A1003 Emergency

在这里插入图片描述

Sample Input:

5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1

Sample Output:

2 4
wordmeaning
scatteredadj. 分散的稀疏的
  • 分析:由输出可知,需求
  1. 最短路径(有权值相同)的条数
  2. 累计人头最多(权值相同时,选择累计点权最大的那条路径)
  • 思路1:
    使用Dijkstra找最小路,在此基础上增设if( == )来处理权值相等的情况
    ->1:使用一个numL[maxn]数组:因为相同最小路径数是所有分支数相乘(每次遇到分支都有不同的选择,排列组合起来),所以需要用数组(初始1),每次找到最小路径,就继承上一个值,只有当找到权值相等的两条路径时,numL[nextC] (上次遍历到相等节点时,就继承过了值)累加上一个节点numL[mid](到中介点的最小路径数)
    ->2:用一个类似于d[]的数组numT[],累计当前最大点权,当遇到==情况时,只有通过中介点mid,能使numT[]变得更大时,才更新numT[]

  • code1:

#include <stdio.h>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 1010;
const int INF = 0x3fffffff;
int N, M, C1, C2;	//n:城市数, M:load数,C1:出发城市 C2:目标城市
int numTeam[maxn];	//各城市救援队人数
int numT[maxn];		//当前到该城市的最多人数 
int L[maxn];	//当前最短路径表,初始位INF 
int minL[maxn];	//统计最小路径数
bool flag[maxn] = {false};	//dijkstra标记数组,记录当前以访问结点true
struct node{
	int id;	//目标城市号,从0开始
	int length;	//救援队人数 
};
vector<node> Map[maxn];

void Dijkstra(){
	fill(flag, flag + maxn, false);
	memset(minL, 0, sizeof(minL));
	memset(numT, 0, sizeof(numT));
	fill(L, L + maxn, INF);
	L[C1] = 0;
	numT[C1] = numTeam[C1];
	minL[C1] = 1;
	for(int i = 0; i < N; ++i){
		int mid = -1, MIN = INF;
		for(int j = 0; j < N; ++j){
			if(flag[j] == false && L[j] < MIN){
					mid = j;
					MIN = L[j];
			}
		}
		if(mid == -1) return;
		flag[mid] = true;
		for(int k = 0; k < Map[mid].size(); ++k){
			int nextC = Map[mid][k].id;
			if(flag[nextC] == false){
				if(L[mid] + Map[mid][k].length < L[nextC]){
					L[nextC] = L[mid] + Map[mid][k].length;	
					numT[nextC] = numT[mid] + numTeam[nextC];
					minL[nextC] = minL[mid];
				}else if(L[mid] + Map[mid][k].length == L[nextC]){
				//如果路径长度相同,累计点权最大(可以更优),更新路径 
					if(numTeam[nextC] + numT[mid] > numT[nextC]){
						numT[nextC] = numT[mid] + numTeam[nextC];
					}
					minL[nextC] += minL[mid];	//minL[c2]即到目的地最短路径数 	
					//!!!:不能简单的+1,设mid结点之前重复的路径数为n,mid之前每多一条路径,总路径数多了n,所以要用数组继承n 
				}
			} 
		}
	}
}

int main(){
	scanf("%d %d %d %d", &N, &M, &C1, &C2);
	for(int i = 0; i < N; ++i)	
		scanf("%d", &numTeam[i]);
	int c1, c2, l;
	for(int i = 0; i < M; ++i){
		scanf("%d %d %d", &c1, &c2, &l);
		node nextC;
		nextC.id = c2;
		nextC.length = l;
		Map[c1].push_back(nextC);
		nextC.id = c1;
		nextC.length = l;
		Map[c2].push_back(nextC);
	}
	Dijkstra();
	printf("%d %d", minL[C2], numT[C2]);
//test图的输入:
//	for(int i = 0; i < 5; ++i){
//		cout << i <<": ";
//		for(int j = 0; j < Map[i].size(); ++j)
//			cout << Map[i][j].id << " " << Map[i][j].length << "||";
//		cout <<endl;
//	}
	return 0;
} 
  • T2 code:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1100;
const int INF = 0x3fffffff;
int G[maxn][maxn], d[maxn], hands[maxn], dh[maxn], num[maxn];
bool vis[maxn];

void Dijkstra(int s, int e, int n){
//	fill(G[0], G[0] + maxn * maxn, INF);	//Wrong 1: G的填充应在初始化前,不然覆盖掉了 
	fill(d, d + maxn, INF);
	memset(dh, 0, sizeof(dh));
	memset(vis, 0, sizeof(vis));
	d[s] = 0;
	dh[s] = hands[s];
	num[s] = 1;
//	vis[s] = true;
	for(int i = 0; i < n; ++i){
		int now = -1, Min = INF;
		for(int j = 0; j < n; ++j){
			if(vis[j] == false && d[j] < Min){
				Min = d[j];
				now = j;
			}
		}
		if(now == -1 || now == e) return;	//剪枝
		vis[now] = true;
		for(int j = 0; j < n; ++j){
			if(vis[j] == false && G[now][j] != INF){
				if(d[now] + G[now][j] < d[j]){
					d[j] = d[now] + G[now][j];
					dh[j] = dh[now] + hands[j];
					num[j] = num[now];
				}else if(d[now] + G[now][j] == d[j]){
					num[j] += num[now];
					if(dh[now] + hands[j] > dh[j]){
						dh[j] = dh[now] + hands[j];
					}						
				}
			}
		}
	}
} 

int main(){
	int n, m, start, end;
	scanf("%d %d %d %d", &n, &m, &start, &end);
	for(int i = 0; i < n; ++i){
		scanf("%d", &hands[i]);
	}	
	fill(G[0], G[0] + maxn * maxn, INF);	
	for(int i = 0; i < m; ++i){
		int c1, c2, lenth;
		scanf("%d %d %d", &c1, &c2, &lenth);
		G[c1][c2] = lenth;
		G[c2][c1] = lenth;
	}
	Dijkstra(start, end, n);
	printf("%d %d", num[end], dh[end]);
	return 0;
} 
  • 思路2:
    同1,存储方式为 邻接矩阵版
  • code2:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn = 510;
const int INF = 1000000000;

int N, M, C1, C2;
int T_num[maxn], G[maxn][maxn];
int d[maxn], p[maxn];	//d:当前最大路径表,p:当前最多人头表 
int L_num[maxn];	//统计最短路径数
bool flag[maxn] = {false};
 
void Dijkstra(){
	fill(d, d + maxn, INF);
	memset(p, 0, sizeof(p));
	memset(L_num, 0, sizeof(L_num));
	d[C1] = 0;
	p[C1] = T_num[C1];	
	L_num[C1] = 1;	//初始为1条路径 
	for(int i = 0; i < N; ++i){
		int mid = -1, MIN = INF;
		for(int j = 0; j < N; ++j){
			if(flag[j] == false && d[j] < MIN){
				mid = j;
				MIN = d[j]; 
			}
		}
		if(mid == -1) return;
		flag[mid] = true;
		for(int k = 0; k < N; ++k){
			if(flag[k] == false && G[mid][k] != INF){
				if(G[mid][k] + d[mid] < d[k]){
					d[k] = G[mid][k] + d[mid];
					p[k] = p[mid] + T_num[k];
					L_num[k] = L_num[mid]; 
				}else if(G[mid][k] + d[mid] == d[k]){
					if(p[k] < p[mid] + T_num[k]){
					//如果通过中介mid到达下一节点,使情况更优(这里是人头更多),才更新 
						d[k] = G[mid][k] + d[mid];
						p[k] = p[mid] + T_num[k];
					}
					//!!!:Wrong:最短路径条数与点权无关,必须写在外面 
					L_num[k] += L_num[mid];
				}
			}
		}
	}
}

int main(){
	scanf("%d %d %d %d",&N, &M, &C1, &C2);
	for(int i = 0; i < N; ++i)
		scanf("%d", &T_num[i]);
	fill(G[0], G[0]+maxn*maxn, INF);
	int c1, c2, w;
	for(int i = 0; i < M; ++i){
		scanf("%d %d %d", &c1, &c2, &w);
		G[c1][c2] = w;
		G[c2][c1] = w;
	}
	Dijkstra();
	printf("%d %d", L_num[C2], p[C2]);
	return 0;
}
  • 思路3:
    Dijkstra只负责找最小路径,不区分选择哪条,但要用一个vector<int> pre[maxn]记录下所有的最小路径,方法为:每次"优化"时将前驱(中介跳点mid)加入pre[next],记录next的前驱,注意:只有两条路径权值相等时,next才有多个前驱;其他情况下,因为对d[k]的优化可能有多次,会加入很多前驱,所以if(<)每次push前驱前要先clean清空pre[],只保留最后一个即最优的那个前驱
    =》得到pre数组:
    通过DFS遍历得到结果:使用两个全局vector,一个tmp记录当前路径,一个res保存全局最优的路径
    ->1.使用一个计数器cnt,每次遍历达到叶节点cnt++,来记录路径数
    ->2.一个全局optV(初始化0)记录最终的累计点权,每遍历完一条路径,将该路径的点权累加起来与optV相比,若更优则更新并将路径保存到res,否则尝试下一条路

  • code3:

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 510;
const int INF = 1000000000;
int G[maxn][maxn], d[maxn];
bool flag[maxn] = {false};
vector<int> pre[maxn];	//记录每个结点的“可选”前驱,即只满足路径最短这一个条件的前驱 
int N, M, C1, C2;
int numT[maxn];

void Dijkstra(int c){
	fill(d, d+maxn, INF);
	d[c] = 0;
	for(int i = 0; i < N; ++i){
		int mid = -1, MIN = INF;
		for(int j = 0; j < N; ++j){
			if(flag[j] == false && d[j] < MIN){
				mid = j;
				MIN = d[j];
			}
		}

		if(mid == -1) return;
		flag[mid] = true;
		for(int k = 0; k < N; ++k){
			if(flag[k] == false && G[mid][k] != INF){
			//!!!:别忘了:G != INF ->有路可走 
				if(G[mid][k] + d[mid] < d[k]){
					d[k] = G[mid][k] + d[mid];
					pre[k].clear();
					pre[k].push_back(mid);
				}else if(G[mid][k] + d[mid] == d[k]){
//					d[k] = G[mid][k] + d[mid];	//没意义== 
					pre[k].push_back(mid);	
				}
			}
		}
	}
}
vector<int> path, tmp;	//tmp存放一条临时路径,path存放当前最优路径
int optV = 0;  
int cnt = 0;	//记录路径数 
void DFS(int v, int r){	//v为当前访问结点, r为根节点即C1(起始结点) 
	if(v == r){
		cnt++; 
		tmp.push_back(r);	//根节点是if的判断条件,所以要单独push
		int value = 0;	//记录全局最优optV,防止被修改
		for(int i = tmp.size()-1; 0 <= i; --i){
		//tmp里存放的是逆序的,即从叶节点到根 
			int id = tmp[i];
			value += numT[id];	//累加tmp路径所有节点的点权 
		}
		if(value > optV){
			optV = value;
			path = tmp;
		}
		tmp.pop_back();	//把刚才加入的节点删除???回溯吗? 
		return;	
	}
	tmp.push_back(v);
	for(int i = 0; i < pre[v].size(); ++i){
		DFS(pre[v][i], r);	//对v的前驱继续DFS 
	}
	tmp.pop_back();	//遍历完该节点的所有前驱后删除该节点 
} 

int main(){
	scanf("%d %d %d %d", &N, &M, &C1, &C2);
	for(int i = 0; i < N; ++i)
		scanf("%d", &numT[i]);
	int c1, c2, w;
	fill(G[0], G[0]+maxn*maxn, INF);
	for(int i = 0; i < M; ++i){
		scanf("%d %d %d", &c1, &c2, &w);
		G[c1][c2] = w;
		G[c2][c1] = w;
	}
	Dijkstra(C1);
	DFS(C2, C1);
	printf("%d %d", cnt, optV);
	return 0;
}

  • T2 code:
#include <bits/stdc++.h>
#include <vector>
using namespace std;
const int maxn = 1100, INF = 0x3fffffff;
int G[maxn][maxn], d[maxn], hands[maxn];
bool vis[maxn];
vector<int> pre[maxn];

void Dijkstra(int start, int end, int n){
	fill(d, d + maxn, INF);
	memset(vis, 0, sizeof(vis));
	d[start] = 0;
	for(int i = 0; i < n; ++i){
		int now = -1, Min = INF;
		for(int j = 0; j < n; ++j){
			if(vis[j] == false && d[j] < Min){
				Min = d[j];
				now = j;
			}
		}
		if(now == -1 || now == end) return;
		vis[now] = true;
		for(int j = 0; j < n; ++j){
			if(vis[j] == false && G[now][j] != INF){
				if(d[now] + G[now][j] < d[j]){
					d[j] = d[now] + G[now][j];
					pre[j].clear();
					pre[j].push_back(now);
				}else if(d[now] + G[now][j] == d[j]){
					pre[j].push_back(now);					
				}
			}
		}
	}
}

int cnt_p = 0, max_hands = 0;
vector<int> tmp;
void DFS(int id, int start){
	tmp.push_back(id);
	if(id == start){
//		tmp.push_back(id);
		cnt_p++;
		int cnt_hands = 0;
		for(int i = 0; i < tmp.size(); ++i){
			cnt_hands += hands[tmp[i]];
		}
		max_hands = max(max_hands, cnt_hands);
//		tmp.pop_back();
		return;
	}
	for(int i = 0; i < pre[id].size(); ++i){
		int nex = pre[id][i];
		DFS(nex, start);
		tmp.pop_back();
	}
}

int main(){
	int n, m, start, end;
	scanf("%d %d %d %d", &n, &m, &start, &end);
	for(int i = 0; i < n; ++i){
		scanf("%d", &hands[i]);
	}
	fill(G[0], G[0] + maxn * maxn, INF);
	for(int i = 0; i < m; ++i){
		int c1, c2, len;
		scanf("%d %d %d", &c1, &c2, &len);
		G[c1][c2] = len;
		G[c2][c1] = len;
	}
	Dijkstra(start, end, n);
	DFS(end, start);
	printf("%d %d", cnt_p, max_hands);
	return 0;
}
  • T3 code: 堆优化
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010, INF = 0x3fffffff;
int hands[maxn], G[maxn][maxn], d[maxn];
bool vis[maxn];

struct node
{
    int id, d;
    bool operator < (const node & tmp) const
    {
        return d > tmp.d;
    }
};

vector<int> pre[maxn];
void Dijkstra(int start, int dest, int n)
{
    priority_queue<node> pq;
    fill(d, d + maxn, INF);
    memset(vis, false, sizeof(vis));
    d[start] = 0;
    pq.push(node{start, 0});
    while(!pq.empty())
    {
        node now = pq.top();
        pq.pop();
        if(now.id == dest) return;
        if(vis[now.id]) continue;   //!!!
        vis[now.id] = true;
        for(int i = 0; i < n; ++i)
        {
            if(vis[i] == false && G[now.id][i] != 0)
            {
                if(now.d + G[now.id][i] < d[i])
                {
                    d[i] = now.d + G[now.id][i];
                    pre[i].clear();
                    pre[i].push_back(now.id);
                    pq.push(node{i, d[i]});
                }else if(now.d + G[now.id][i] == d[i])
                {
                    pre[i].push_back(now.id);
                    pq.push(node{i, d[i]}); //二次更新!!!!
                }
            }
        }
    }
}

void DFS(int id, int dest, int sum_hands, int & max_hands, int & cnt)
{
    if(pre[id].size() == 0)
    {
        cnt++;
        max_hands = max(max_hands, sum_hands);
        return;
    }
    for(int i = 0; i < pre[id].size(); ++i)
    {
        int nex = pre[id][i];
        DFS(nex, dest, sum_hands + hands[nex], max_hands, cnt);
    }
}

int main()
{
    int nc, nr, s, e;
    scanf("%d %d %d %d", &nc, &nr, &s, &e);
    for(int i = 0; i < nc; ++i)
    {
        scanf("%d", &hands[i]);
    }
    for(int i = 0; i < nr; ++i)
    {
        int c1, c2, len;
        scanf("%d %d %d", &c1, &c2, &len);
        G[c1][c2] = G[c2][c1] = len;
    }
    Dijkstra(s, e, nc);
    int max_hands = 0, cnt = 0;
    DFS(e, s, hands[e], max_hands, cnt);
    printf("%d %d", cnt, max_hands);
    return 0;
}
  • T3 code: 堆优化版
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010, INF = 0x3fffffff;
int hands[maxn], G[maxn][maxn], d[maxn], dhands[maxn], cnt[maxn];
bool vis[maxn];

struct node
{
    int id, d;
    bool operator < (const node & tmp) const
    {
        return d > tmp.d;
    }
};
void Dijkstra(int start, int dest, int n)
{
    priority_queue<node> pq;
    fill(d, d + maxn, INF);
    memset(vis, false, sizeof(vis));
    d[start] = 0;
    dhands[start] = hands[start];
    cnt[start] = 1;
    pq.push(node{start, 0});
    while(!pq.empty())
    {
        node now = pq.top();
        pq.pop();
        if(now.id == dest) return;
        if(vis[now.id]) continue;   //!!!
        vis[now.id] = true;
        for(int i = 0; i < n; ++i)
        {
            if(vis[i] == false && G[now.id][i] != 0)
            {
                if(now.d + G[now.id][i] < d[i])
                {
                    d[i] = now.d + G[now.id][i];
                    dhands[i] = dhands[now.id] + hands[i];
                    cnt[i] = cnt[now.id];
                    pq.push(node{i, d[i]});
                }else if(now.d + G[now.id][i] == d[i])
                {
                    if(dhands[i] < dhands[now.id] + hands[i])
                    {
                        dhands[i] = dhands[now.id] + hands[i];
                        pq.push(node{i, d[i]}); //二次更新!!!!
                    }
                    cnt[i] += cnt[now.id];
                }
            }
        }
    }
}

int main()
{
    int nc, nr, s, e;
    scanf("%d %d %d %d", &nc, &nr, &s, &e);
    for(int i = 0; i < nc; ++i)
    {
        scanf("%d", &hands[i]);
    }
    for(int i = 0; i < nr; ++i)
    {
        int c1, c2, len;
        scanf("%d %d %d", &c1, &c2, &len);
        G[c1][c2] = G[c2][c1] = len;
    }
    Dijkstra(s, e, nc);
    printf("%d %d", cnt[e], dhands[e]);
    return 0;
}
  • 思路4:
    Bellman_Ford算法版,参照算法笔记

  • code4:

#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
const int maxn = 510;
const int INF = 0x3fffffff;
struct node{
	int v, dis;
	node(int _v, int _dis) : v(_v), dis(_dis){};
};
vector<node> Adj[maxn];
int n, m, st, ed, weight[maxn];
//w[maxn]:记录最大点权,即人头数	num[maxn]:记录最短路径条数 
int d[maxn], w[maxn], num[maxn];
set<int> pre[maxn];	//前驱

void Bellman_ford(int s){
	fill(d, d+maxn, INF);
	memset(num, 0, sizeof(num));
	memset(w, 0, sizeof(w));
	d[s] = 0;
	w[s] = weight[s];
	num[s] = 1;
	for(int i = 0; i < n-1; ++i){
		for(int u = 0; u < n; ++u){
			for(int j = 0; j < Adj[u].size(); ++j){
				int v = Adj[u][j].v;
				int dis = Adj[u][j].dis;
				if(d[u] + dis < d[v]){
					d[v] = d[u] + dis;
					w[v] = w[u] + weight[v];
					num[v] = num[u];
					pre[v].clear();
					pre[v].insert(u);
				}else if(d[u] + dis == d[v]){
					if(w[u] + weight[v] > w[v]){
						w[v] = w[u] + weight[v];
					}
					pre[v].insert(u);
					num[v] = 0;	//!!!:WHY: 重新统计num -》 BF算法会重复访问一条边,导致num[]重复累加,故每次都要重新更新
					set<int>::iterator it;
					for(it = pre[v].begin(); it != pre[v].end(); ++it){
						num[v] += num[*it];
					}
				}
			}
		}
	}
} 
int main(){
	scanf("%d %d %d %d", &n, &m, &st, &ed);
	for(int i = 0; i < n; ++i){
		scanf("%d", &weight[i]);	//读入点权 
	}
	int u, v, wt;
	for(int i = 0; i < m; ++i){
		scanf("%d %d %d", &u, &v, &wt);
		Adj[u].push_back(node(v, wt));
		Adj[v].push_back(node(u, wt));
	}
	Bellman_ford(st);
	printf("%d %d", num[ed], w[ed]);
	return 0;
}
  • BF:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010, INF = 0x3fffffff;
int d[maxn], weight[maxn], dw[maxn], cnt[maxn];
struct node
{
    int nex, dis;
};
vector<node> G[maxn];
set<int> pre[maxn];
bool BF(int start, int n)
{
    fill(d, d + maxn, INF);
    d[start] = 0; dw[start] = weight[start]; cnt[start] = 1;
    for(int i = 0; i < n-1; ++i)
    {
        for(int u = 0; u < n; ++u)
        {
            for(int j = 0; j < G[u].size(); ++j)
            {
                int v = G[u][j].nex;
                int len = G[u][j].dis;
                if(d[u] + len < d[v])
                {
                    d[v] = d[u] + len;
                    dw[v] = dw[u] + weight[v];
                    cnt[v] = cnt[u];
                    pre[v].clear();
                    pre[v].insert(u);
                }else if(d[u] + len == d[v])
                {
                    if(dw[u] + weight[v] > dw[v])
                    {
                        dw[v] = dw[u] + weight[v];
                    }
                    pre[v].insert(u);
                    cnt[v] = 0; //别忘了清零!!
                    for(auto it : pre[v]) cnt[v] += cnt[it];
                }
            }
        }
    }
    for(int u = 0; u < n; ++u)
    {
        for(int j = 0; j < G[u].size(); ++j)
        {
            int v = G[u][j].nex;
            int len = G[u][j].dis;
            if(d[u] + len < d[v])
            {
                return false;
            }
        }
    }
    return true;
}
int main()
{
    int n, m, s, e;
    scanf("%d %d %d %d", &n, &m, &s, &e);
    for(int i = 0; i < n; ++i) scanf("%d", &weight[i]);
    for(int i = 0; i < m; ++i)
    {
        int c1, c2, len;
        scanf("%d %d %d", &c1, &c2, &len);
        G[c1].push_back(node{c2, len});
        G[c2].push_back(node{c1, len});
    }
    BF(s, n);
    printf("%d %d", cnt[e], dw[e]);
    return 0;
}

  • 优化:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 500, INF = 0x3fffffff;
int weight[maxn], d[maxn], dw[maxn], cnt[maxn];
struct node
{
    int nex, dis;
};
vector<node> G[maxn];

unordered_set<int> pre[maxn];
bool BF(int start, int n)
{
    fill(d, d + maxn, INF);
    d[start] = 0; dw[start] = weight[start]; cnt[start] = 1;
    for(int i = 0; i < n-1; ++i)
    {
        bool isUpdate = false;
        for(int now = 0; now < n; ++now)
        {
            for(int j = 0; j < G[now].size(); ++j)
            {
                int nex = G[now][j].nex;
                int dis = G[now][j].dis;
                if(d[now] + dis < d[nex])
                {
                    d[nex] = d[now] + dis;
                    dw[nex] = dw[now] + weight[nex];
                    cnt[nex] = cnt[now];
                    pre[nex].clear();
                    pre[nex].insert(now);
                    isUpdate = true;
                }else if(d[now] + dis == d[nex])
                {
                    if(dw[now] + weight[nex] > dw[nex])
                    {
                        dw[nex] = dw[now] + weight[nex];
                        isUpdate = true;
                    }
                    pre[nex].insert(now);
                    cnt[nex] = 0;
                    for(int it : pre[nex]) cnt[nex] += cnt[it];
                }
            }
        }
        if(!isUpdate) return true;
    }
    for(int now = 0; now < n; ++now)
    {
        for(int j = 0; j < G[now].size(); ++j)
        {
            int nex = G[now][j].nex;
            int dis = G[now][j].dis;
            if(d[now] + dis < d[nex])
            {
                return false;
            }
        }
    }
    return true;
}

int main()
{
    int n, m, s, e;
    scanf("%d %d %d %d", &n, &m, &s, &e);
    for(int i = 0; i < n; ++i) scanf("%d", &weight[i]);
    for(int i = 0; i < m; ++i)
    {
        int c1, c2, len;
        scanf("%d %d %d", &c1, &c2, &len);
        G[c1].push_back(node{c2, len});
        G[c2].push_back(node{c1, len});
    }
    BF(s, n);
    printf("%d %d", cnt[e], dw[e]);
    return 0;
}

  • BF + DFS:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010, INF = 0x3fffffff;
int d[maxn], weight[maxn];
struct node
{
    int nex, dis;
};
vector<node> G[maxn];
set<int> pre[maxn];
bool BF(int start, int n)
{
    fill(d, d + maxn, INF);
    d[start] = 0;
    for(int i = 0; i < n-1; ++i)
    {
        for(int u = 0; u < n; ++u)
        {
            for(int j = 0; j < G[u].size(); ++j)
            {
                int v = G[u][j].nex;
                int len = G[u][j].dis;
                if(d[u] + len < d[v])
                {
                    d[v] = d[u] + len;
                    pre[v].clear();
                    pre[v].insert(u);
                }else if(d[u] + len == d[v])
                {
                    pre[v].insert(u);
                }
            }
        }
    }
    for(int u = 0; u < n; ++u)
    {
        for(int j = 0; j < G[u].size(); ++j)
        {
            int v = G[u][j].nex;
            int len = G[u][j].dis;
            if(d[u] + len < d[v])
            {
                return false;
            }
        }
    }
    return true;
}
vector<int> tmp, ans;
void DFS(int id, int start, int & cnt, int & max_hands)
{
    tmp.push_back(id);
    if(id == start)
    {
        cnt++;
        int sum_hands = 0;
        for(int i = tmp.size()-1; i >= 0; --i)
        {
            int now = tmp[i];
            sum_hands += weight[now];
            //计算当前路径的各标尺
        }
        if(sum_hands > max_hands)
        {
            max_hands = sum_hands;
        }
        //优化各标尺
        tmp.pop_back();
        return;
    }
    for(auto it : pre[id])
    {
        DFS(it, start, cnt, max_hands);
    }
    tmp.pop_back();
}
int main()
{
    int n, m, s, e;
    scanf("%d %d %d %d", &n, &m, &s, &e);
    for(int i = 0; i < n; ++i) scanf("%d", &weight[i]);
    for(int i = 0; i < m; ++i)
    {
        int c1, c2, len;
        scanf("%d %d %d", &c1, &c2, &len);
        G[c1].push_back(node{c2, len});
        G[c2].push_back(node{c1, len});
    }
    BF(s, n);
    int cnt = 0, Max = 0;
    DFS(e, s, cnt, Max);
    printf("%d %d", cnt, Max);
    return 0;
}

  • SPFA:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 500, INF = 0x3fffffff;
int weight[maxn], d[maxn], dw[maxn], cnt[maxn];
struct node
{
    int nex, dis;
};
vector<node> G[maxn];

int cnt_inq[maxn];
bool inq[maxn];
unordered_set<int> pre[maxn];
bool SPFA(int start, int n)
{
    fill(d, d + maxn, INF);
    d[start] = 0; dw[start] = weight[start]; cnt[start] = 1;
    queue<int> q;
    q.push(start);
    inq[start] = true;
    cnt_inq[start]++;
    while(!q.empty())
    {
        int now = q.front();
        q.pop();
        inq[now] = false;
        for(int i = 0; i < G[now].size(); ++i)
        {
            int nex = G[now][i].nex;
            int dis = G[now][i].dis;
            if(d[now] + dis < d[nex])
            {
                d[nex] = d[now] + dis;
                dw[nex] = dw[now] + weight[nex];
                cnt[nex] = cnt[now];
                pre[nex].clear();
                pre[nex].insert(now);
                if(inq[nex] == false)
                {
                    q.push(nex);
                    inq[nex] = true;
                    cnt_inq[nex]++;
                    if(cnt_inq[nex] >= n) return false;
                }
            }else if(d[now] + dis == d[nex])
            {
                if(dw[now] + weight[nex] > dw[nex])
                {
                    dw[nex] = dw[now] + weight[nex];
                }
                if(inq[nex] == false)   //nex是一条新的最短路分支,要将nex加入队列,所有应写在上面那个if的外面!!
                {
                    q.push(nex);
                    inq[nex] = true;
                    cnt_inq[nex]++;
                    if(cnt_inq[nex] >= n) return false;
                }
                pre[nex].insert(now);
                cnt[nex] = 0;
                for(int it : pre[nex]) cnt[nex] += cnt[it];
            }
        }
    }
    return true;
}
int main()
{
    int n, m, s, e;
    scanf("%d %d %d %d", &n, &m, &s, &e);
    for(int i = 0; i < n; ++i) scanf("%d", &weight[i]);
    for(int i = 0; i < m; ++i)
    {
        int c1, c2, len;
        scanf("%d %d %d", &c1, &c2, &len);
        G[c1].push_back(node{c2, len});
        G[c2].push_back(node{c1, len});
    }
    SPFA(s, n);
    printf("%d %d", cnt[e], dw[e]);
    return 0;
}

  • SPFA + DFS:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010, INF = 0x3fffffff;
int d[maxn], numq[maxn], weight[maxn];
bool inq[maxn];
struct node
{
    int nex, dis;
};
vector<node> G[maxn];

set<int> pre[maxn];
bool SPFA(int start, int n)
{
    fill(d, d + maxn, INF);
    queue<int> q;
    q.push(start);
    inq[start] = true;  //在队中
    numq[start]++;  //入队次数
    d[start] = 0;
    while(!q.empty())
    {
        int mid = q.front();
        q.pop();
        inq[mid] = false;
        for(int i = 0; i < G[mid].size(); ++i)
        {
            int nex = G[mid][i].nex;
            int len = G[mid][i].dis;
            if(d[mid] + len < d[nex])
            {
                d[nex] = d[mid] + len;
                pre[nex].clear();
                pre[nex].insert(mid);
                if(inq[nex] == false)
                {
                    q.push(nex);
                    inq[nex] = true;
                    numq[nex]++;
                    if(numq[nex] >= n) return false;
                }
            }else if(d[mid] + len == d[nex])
            {
            	//WRONG!!!!!!!!!!这里错了!看下一个代码
                pre[nex].insert(mid);
            }
        }
    }
    return true;
}
vector<int> tmp;
void DFS(int id, int start, int & cnt, int & max_hands)
{
    tmp.push_back(id);
    if(id == start)
    {
        cnt++;
        int sum_hands = 0;
        for(int i = tmp.size()-1; i >= 0; --i)
        {
            int now = tmp[i];
            sum_hands += weight[now];
        }
        if(sum_hands > max_hands)
        {
            max_hands = sum_hands;
        }
        tmp.pop_back();
        return;
    }
    for(auto it : pre[id]) DFS(it, start, cnt, max_hands);
    tmp.pop_back();
}
int main()
{
    int n, m, s, e;
    scanf("%d %d %d %d", &n, &m, &s, &e);
    for(int i = 0; i < n; ++i) scanf("%d", &weight[i]);
    for(int i = 0; i < m; ++i)
    {
        int c1, c2, len;
        scanf("%d %d %d", &c1, &c2, &len);
        G[c1].push_back(node{c2, len});
        G[c2].push_back(node{c1, len});
    }
    SPFA(s, n);
    int cnt = 0, Max = 0;
    DFS(e, s, cnt, Max);
    printf("%d %d", cnt, Max);
    return 0;
}

  • 改正 SPFA
#include <bits/stdc++.h>
using namespace std;
const int maxn = 500, INF = 0x3fffffff;
int weight[maxn], d[maxn];
struct node
{
    int nex, dis;
};
vector<node> G[maxn];

int cnt_inq[maxn];
bool inq[maxn];
unordered_set<int> pre[maxn];
bool SPFA(int start, int n)
{
    fill(d, d + maxn, INF);
    d[start] = 0;
    queue<int> q;
    q.push(start);
    inq[start] = true;
    cnt_inq[start]++;
    while(!q.empty())
    {
        int now = q.front();
        q.pop();
        inq[now] = false;
        for(int i = 0; i < G[now].size(); ++i)
        {
            int nex = G[now][i].nex;
            int dis = G[now][i].dis;
            if(d[now] + dis < d[nex])
            {
                d[nex] = d[now] + dis;
                pre[nex].clear();
                pre[nex].insert(now);
                if(inq[nex] == false)
                {
                    q.push(nex);
                    inq[nex] = true;
                    cnt_inq[nex]++;
                    if(cnt_inq[nex] >= n) return false;
                }
            }else if(d[now] + dis == d[nex])
            {
                if(inq[nex] == false)
                {
                    q.push(nex);
                    inq[nex] = true;
                    cnt_inq[nex]++;
                    if(cnt_inq[nex] >= n) return false;
                }
                pre[nex].insert(now);
            }
        }
    }
    return true;
}
void DFS(int id, int s, int & cnt, int cur_w, int & max_w)
{
    if(id == s)
    {
        cnt++;
        max_w = max(max_w, cur_w);
        return;
    }
    for(auto it : pre[id])
    {
        DFS(it, s, cnt, cur_w + weight[it], max_w);
    }
}
int main()
{
    int n, m, s, e;
    scanf("%d %d %d %d", &n, &m, &s, &e);
    for(int i = 0; i < n; ++i) scanf("%d", &weight[i]);
    for(int i = 0; i < m; ++i)
    {
        int c1, c2, len;
        scanf("%d %d %d", &c1, &c2, &len);
        G[c1].push_back(node{c2, len});
        G[c2].push_back(node{c1, len});
    }
    SPFA(s, n);
    int cnt = 0, max_w = 0;
    DFS(e, s, cnt, weight[e], max_w);
    printf("%d %d", cnt, max_w);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值