1.这是解决三种问题的第一种方法
例题描述:
pat1003
本题只是要求三种问题中的新增点权(每个城市的救援小组数目)和最短路径条数,再次基础上把新增边权的我也加上了,即每条边的花费。
其中把无向边当作两条方向相反的有向边存储,用vector数组实现链表存储
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <string.h>
using namespace std;
const int INF = 0x3fffffff;
const int maxn = 1e3+10;
struct Node{
int adjvex;
int edge_weight;
int spend;
};
Node node;
vector<Node> Agraph[maxn];
bool visit[maxn] = {
0};//遍历结点记忆数组
int min_dis[maxn];//min_dis[u]:意思是从开始节点到u的最短距离
int path[maxn];//存储从开始结点到某点的最短路径,用递归输出
int rescue_num[maxn] = {
0};//各个城市的救援小组数目
//注意:下面两个要求的东西得先满足时最短路径再说
int rescue_nummax[maxn] = {
0};//rescue_nummax[u]:意思是从开始节点到u的所有的最短路径中的最大救援小组数目
int route_num[maxn] = {
0};//route_num[u]:意思是从开始节点到u的路径条数
vector<Node> Agraph_spend[maxn];//存储花费
int min_spend[maxn] = {
0};//min_spend[u]:意思是从开始节点到u的所有的最短路径中的最少花费
int n,m;
void Dijkstra(int v)
{
fill(min_dis,min_dis + n,INF);
min_dis[v] = 0;
fill(min_spend,min_spend + n,INF);
min_spend[v] = 0;
rescue_nummax[v] = rescue_num[v];
route_num[v] = 1;
for(int i = 0;i < n;i++)
{
path[i] = i;
}
for(int i = 0;i < n;i++)
{
int u = -1,MIN = INF;
for(int j = 0;j < n;j++)
{
if(visit[j] == false&&min_dis[j] < MIN)
{
u = j;
MIN = min_dis[j];
}
}
if(u == -1) return;
visit[u] = true;
for(int j = 0;j < (int)Agraph[u].size();j++)//u->j
{
node = Agraph[u][j];
if(visit[node.adjvex] == false)
{
if(min_dis[u] + node.edge_weight < min_dis[node.adjvex])
{
min_dis[node.adjvex] = min_dis[u] + node.edge_weight;
path[node.adjvex] = u;
rescue_nummax[node.adjvex] = rescue_nummax[u] + rescue_num[node.adjvex];
route_num[node.adjvex] = route_num[u];
min_spend[node.adjvex] = min_spend[u] + node.spend;
}else if(min_dis[u] + node.edge_weight == min_dis[node.adjvex]){
route_num[node.adjvex] += route_num[u];
if(rescue_nummax[u] + rescue_num[node.adjvex] > rescue_nummax[node.adjvex])
rescue_nummax[node.adjvex] = rescue_nummax[u] + rescue_num[node.adjvex];
if(min_spend[u] + node.spend < min_spend[node.adjvex])
{
min_spend[node.adjvex] = min_spend[u] + node.spend;
path[node.adjvex] = u;
}
}
}
}
}
}
void DFS_path(int start,int v)
{
if(start == v)
{
cout<<start;
return;
}
else{
DFS_path(start,path[v]);
cout<<" "<<v;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int vex1,vex2,weight,start,i,end,spend;
cin>>n>>m>>start>>end;
for(i = 0;i < n; i++)
cin>>rescue_num[i];
for(i = 0 ;i < m;i++)
{
cin>>vex1>>vex2>>weight>>spend;
node.adjvex = vex2;
node.spend = spend;
node.edge_weight = weight;
Agraph[vex1].push_back(node);
node.adjvex = vex1;
node.spend = spend;
node.edge_weight = weight;
Agraph[vex2].push_back(node);
}
Dijkstra(start);
cout<<route_num[end]<<" "<<rescue_nummax[end]<<" "<<min_spend[end]<<endl;
DFS_path(start,end);
return 0;
}
2 .测试用例:
5 6 0 2
1 2 1 5 3
0 1 1 3
0 2 2 1
0 3 1 1
1 2 1 5
2 4 1 1
3 4 1 1
上述代码path中保存的最短路径是保证最小花费(新增的边权)的那条最短路径,若想求得最大营救小组数目的最短路径,只需将
if(rescue_nummax[u] + rescue_num[node.adjvex] > rescue_nummax[node.adjvex])
rescue_nummax[node.adjvex] = rescue_nummax[u] + rescue_num[node.adjvex];
if(min_spend[u] + node.spend < min_spend[node.adjvex])
{
min_spend[node.adjvex] = min_spend[u] + node.spend;
path[node.adjvex] = u;
}
替换为
if(rescue_nummax[u] + rescue_num[node.adjvex] > rescue_nummax[node.adjvex])
{
rescue_nummax[node.adjvex] = rescue_nummax[u] + rescue_num[node.adjvex];
path[node.adjvex] = u;
}
if(min_spend[u] + node.spend < min_spend[node.adjvex])
min_spend[node.adjvex] = min_spend[u] + node.spend;
3.第二类方法:先说新增点权的路径数目
即用vector数组型的pre存储某个点的对应多个最短路径的前驱。如本题的前驱关系及pre如下:
可以看出最短路径的最后一个点都是开始点。
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <string.h>
using namespace std;
const int INF = 0x3fffffff;
const int maxn = 1e3+10;
struct Node{
int adjvex;
int edge_weight;
};
Node node;
vector<Node> Agraph[maxn];
bool visit[maxn] = {
0};
int min_dis[maxn];//min_dis[u]:意思是从开始节点到u的最短距离
int rescue_num[maxn];
vector<int> pre[maxn];
vector<int> path,temp;
int n,m,route_num = 0,max_value = 0;
void Dijkstra(int v)
{
fill(min_dis,min_dis + n,INF);
min_dis[v] = 0;
for(int i = 0;i < n;i++)
{
int u = -1,MIN = INF;
for(int j = 0;j < n;j++)
{
if(visit[j] == false&&min_dis[j] < MIN)
{
u = j;
MIN = min_dis[j];
}
}
if(u == -1) return;
visit[u] = true;
for(int j = 0;j < (int)Agraph[u].size();j++)//u->j
{
node = Agraph[u][j];
if(visit[node.adjvex] == false)
{
if(min_dis[u] + node.edge_weight < min_dis[node.adjvex])
{
min_dis[node.adjvex] = min_dis[u] + node.edge_weight;
pre[node.adjvex].clear();
pre[node.adjvex].push_back(u);
}else if(min_dis[u] + node.edge_weight == min_dis[node.adjvex]){
pre[node.adjvex].push_back(u);
}
}
}
}
}
void DFS(int start,int v)
{
if(v == start)
{
route_num++;
temp.push_back(v);
int value = 0;
for(int i = temp.size()-1;i >= 0; i--)
{
value += rescue_num[temp[i]];
}
if(value > max_value)
{
max_value = value;
path = temp;
}
temp.pop_back();
return;
}else{
temp.push_back(v);
for(int i = 0;i < (int)pre[v].size();i++)
DFS(start,pre[v][i]);
temp.pop_back();
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int vex1,vex2,weight,start,i,end,spend;
cin>>n>>m>>start>>end;
for(i = 0;i < n; i++)
cin>>rescue_num[i];
for(i = 0 ;i < m;i++)
{
cin>>vex1>>vex2>>weight;
node.adjvex = vex2;
node.edge_weight = weight;
Agraph[vex1].push_back(node);
node.adjvex = vex1;
node.edge_weight = weight;
Agraph[vex2].push_back(node);
}
Dijkstra(start);
DFS(start,end);
cout<<route_num<<" "<<max_value;
return 0;
}
再来一个题:新增边权
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <string.h>
using namespace std;
const int INF = 0x3fffffff;
const int maxn = 1e3+10;
struct Node{
int adjvex;
int edge_weight;
int spend;
};
Node node;
vector<Node> Agraph[maxn];
bool visit[maxn] = {
0};
int min_dis[maxn];//min_dis[u]:意思是从开始节点到u的最短距离
int rescue_num[maxn];
vector<int> pre[maxn];
vector<int> path,temp;
int n,m,min_value = INF;
void Dijkstra(int v)
{
fill(min_dis,min_dis + n,INF);
min_dis[v] = 0;
for(int i = 0;i < n;i++)
{
int u = -1,MIN = INF;
for(int j = 0;j < n;j++)
{
if(visit[j] == false&&min_dis[j] < MIN)
{
u = j;
MIN = min_dis[j];
}
}
if(u == -1) return;
visit[u] = true;
for(int j = 0;j < (int)Agraph[u].size();j++)//u->j
{
node = Agraph[u][j];
if(visit[node.adjvex] == false)
{
if(min_dis[u] + node.edge_weight < min_dis[node.adjvex])
{
min_dis[node.adjvex] = min_dis[u] + node.edge_weight;
pre[node.adjvex].clear();
pre[node.adjvex].push_back(u);
}else if(min_dis[u] + node.edge_weight == min_dis[node.adjvex]){
pre[node.adjvex].push_back(u);
}
}
}
}
}
void DFS(int start,int v)
{
if(v == start)
{
temp.push_back(v);
int value = 0;
for(int i = temp.size()-1;i > 0; i--)
{
int id = temp[i],idnext = temp[i - 1];
for(int j = 0;j < (int)Agraph[id].size();j++)
{
if(Agraph[id][j].adjvex == idnext)
{
value += Agraph[id][j].spend;
break;
}
}
}
if(value < min_value)
{
min_value = value;
path = temp;
}
temp.pop_back();
return;
}else{
temp.push_back(v);
for(int i = 0;i < (int)pre[v].size();i++)
DFS(start,pre[v][i]);
temp.pop_back();
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int vex1,vex2,weight,start,i,end,spend;
cin>>n>>m>>start>>end;
for(i = 0 ;i < m;i++)
{
cin>>vex1>>vex2>>weight>>spend;
node.adjvex = vex2;
node.spend = spend;
node.edge_weight = weight;
Agraph[vex1].push_back(node);
node.adjvex = vex1;
node.edge_weight = weight;
node.spend = spend;
Agraph[vex2].push_back(node);
}
Dijkstra(start);
DFS(start,end);
for(i = path.size() - 1;i >= 0;i--)
{
cout<<path[i]<<" ";
}
cout<<min_dis[end]<<" "<<min_value;
return 0;
}