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
word | meaning |
---|---|
scattered | adj. 分散的稀疏的 |
- 分析:由输出可知,需求
- 最短路径(有权值相同)的条数
- 累计人头最多(权值相同时,选择累计点权最大的那条路径)
-
思路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;
}