PAT甲级1003 Emergency (25 分)题解

PAT甲级1003 Emergency (25 分)题解_第1张图片PAT甲级1003 Emergency (25 分)题解_第2张图片
\quad 这是一个最短路的题,但要求多了一些,要求我们统计最短路条数,若有多条最短路,需要输出能获得营救队伍最多的值。故需要我们在最忧子结构里面更新两个变量。我用num[v]表示起点s到点v最短路径的条数,res[v]表示起点s到v点所能得到的最多队伍数,故在初始化时候num[s]=1,res[s]=a[s],a[s]表示s点营救队伍数量。最优子结构如下:

if(dis[v]>dis[u]+w)
{
     
	dis[v] = dis[u]+w;
	num[v] = num[u];
	res[v] = res[u]+a[v];
}
else if(dis[v]==dis[u]+w)
{
     
	num[v] += num[u];
	res[v] = max(res[v], res[u]+a[v]);
}

\quad 总程序如下:

#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 501;
int a[maxn];  // 记录每个点营救队伍数目
vector<pair<int, int> > E[maxn];
int vis[maxn], dis[maxn];
int num[maxn], res[maxn];
void dijstra(int s, int t)
{
     
	fill(dis, dis+maxn, 0x3f3f3f3f);
	dis[s] = 0;
	num[s] = 1;
	res[s] = a[s];
	priority_queue<pair<int, int> > q;
	q.push(make_pair(0, s));
	while(!q.empty())
	{
     
		int u = q.top().second;
		q.pop();
		if(vis[u]==1) continue;
		vis[u] = 1;
		for (int i = 0; i < E[u].size(); ++i)
		{
     
			int v = E[u][i].first, w = E[u][i].second;
			if(dis[v]>dis[u]+w)
			{
     
				dis[v] = dis[u]+w;
				num[v] = num[u];
				res[v] = res[u]+a[v];
				if(vis[v]==0) q.push(make_pair(-dis[v], v));
			}
			else if(dis[v]==dis[u]+w)
			{
     
				num[v] += num[u];
				res[v] = max(res[v], res[u]+a[v]);
				if(vis[v]==0) q.push(make_pair(-dis[v], v));
			}
		}
	}
	cout << num[t] << " " << res[t];
}
int main(int argc, char const *argv[])
{
     
	int N, M, s, t;
	cin >> N >> M >> s >> t;
    for(int i = 0; i < N; i++) cin >> a[i];
    while(M--)
    {
     
    	int u, v, w;
    	cin >> u >> v >> w;
    	E[u].push_back(make_pair(v, w));
    	E[v].push_back(make_pair(u, w));
    }
    dijstra(s, t);
	return 0;
}

\quad 这里也给出用spfa求解的程序,需注意的是spfa可能会重复访问一个点,因此在统计最短路径条数的时候需要额外用一个set进行存储和去重的工作。

#include 
#include 
#include 
#include 
#include 
using namespace std;

const int maxn = 1001;
vector<pair<int, int> > E[maxn];
int teams[maxn];
int pathNum[maxn], teamNum[maxn];
int inq[maxn], dis[maxn];
set<int> st[maxn];
void spfa(int s, int t)
{
     
	fill(dis, dis+maxn, 0x3f3f3f3f);
	dis[s] = 0;
	queue<int> q;
	q.push(s);
	inq[s] = 1;
	pathNum[s] = 1;
	teamNum[s] = teams[s];
	while(!q.empty())
	{
     
		int u = q.front();
		q.pop();
		inq[u] = 0;
		for (int i = 0; i < E[u].size(); ++i)
		{
     
			int v = E[u][i].first, w = E[u][i].second;
			if(dis[v]>dis[u]+w)
			{
     
				dis[v] = dis[u]+w;
				pathNum[v] = pathNum[u];
				teamNum[v] = teamNum[u]+teams[v];
				st[v].clear();
				st[v].insert(u);
				if(inq[v]==0) q.push(v), inq[v]=1;
			}
			else if(dis[v]==dis[u]+w)
			{
     
				st[v].insert(u);
				pathNum[v] = 0;  // //因为spfa会重复到一个点 所以可能重复的边
				for(set<int>::iterator it=st[v].begin(); it!=st[v].end(); it++) pathNum[v] += pathNum[*it];
				teamNum[v] = max(teamNum[v], teamNum[u]+teams[v]);
				if(inq[v]==0) q.push(v), inq[v]=1;
			}
		}
	}
	cout << pathNum[t] << " " << teamNum[t];
}
int main(int argc, char const *argv[])
{
     
	int N, M, s, t;
	cin >> N >> M >> s >> t;
    for(int i = 0; i < N; i++) cin >> teams[i];
    while(M--)
    {
     
    	int u, v, w;
    	cin >> u >> v >> w;
    	E[u].push_back(make_pair(v, w));
    	E[v].push_back(make_pair(u, w));
    }
    spfa(s, t);
	return 0;
}

你可能感兴趣的:(PAT甲级,PAT甲级1003,Emergency,(25,分)题解,1003,Emergency,(25,分),最短路径)