题目链接:
题意:
这里有N座城市,这里还有一些连接不同城市的单程直飞航班。(有向图)
可以城市之间的直飞的航班用长度为N的字符串进行表示。如果从第i个城市到达第j个城市的字符为 Y,表示可以从 i 到 j,否则如果字符是 N,表示不可以从 i 到 j。
每座城市都在卖纪念品,城市i的纪念品价值为Ai,;
思考以下的问题:
我想途径一些直达航班,从城市S出发去往T城市(T和S不同!),沿途中,他会去参观经过的城市,并且购买一个纪念品。
如果从城市S到达城市T有多条路线,我选择的路线决定如下:
1、他尽可能地减少从城市S到达城市T的直达航班数。
2、他试图使他所购买的纪念品价值最大化。
请你确定他是否能够从S–>T,如果可以,请找到满足上述条件的路线的纪念品价值总和。
给你Q个查询序对(U,V)对于每次查询,都请输出对应的最大的纪念品价值。
思路:
本题的性质有两个:
- 首先是最小化路径长度
- 其次是最大化经过城市的纪念品的价值总和
若单看最小化路径长度的话,那么就是一个最短路问题,根据数据范围N<=300可以推出:可用floyd算法求解,因为floyd算法比较好写!且并未超过时间复杂度!
但是现在需要考虑第二个条件,实际上就是多开一个数组 sum[i, j]表示从城市 i 到达城市 j 的纪念品价值的总和。但要注意状态转移的思路:如果路径严格变小,那么纪念品价值总和也要跟着变化;如果路径长度相等,则可以去纪念品价值总和的一个最大值!注意初始化!
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 3e2 + 10;
int dist[N][N]; //表示从i城市到j城市最短路径
LL sum[N][N]; //从i城市到j城市的纪念品价值总和
char str[N]; //描述城市之间关系的邻接矩阵
int a[N]; //每座城市的纪念品价值!
int main()
{
int n;
cin >> n;
for (int i=1; i <= n; i ++)
cin >> a[i];
memset (dist, 0x3f, sizeof (dist)); //初始化为无穷大表示不可到达!
for (int i=1; i <= n; i ++)
{
scanf ("%s", str+1); //按行输入!
for (int j=1; j <= n; j ++)
if (str[j] == 'Y')
dist[i][j] = 1, sum[i][j] = 1LL*a[i] + 1LL*a[j];
}
for (int i=1; i <= n; i ++)
dist[i][i]=0, sum[i][i] = 1LL*a[i];
for (int k=1; k <= n; k ++) //枚举从i-->j之间的城市;
for (int i=1; i <= n; i ++) //枚举起点!
for (int j=1; j <= n; j ++) //枚举终点!
{
if (dist[i][j] == dist[i][k] + dist[k][j])
{
dist[i][j] = dist[i][k] + dist[k][j];
sum[i][j] = max(sum[i][j], 1LL*sum[i][k]+1LL*sum[k][j]-1LL*a[k]);
}
else if (dist[i][j] > dist[i][k]+dist[k][j])
{
dist[i][j] = dist[i][k] + dist[k][j];
sum[i][j] = sum[i][k] + sum[k][j] - 1LL* a[k];
}
}
int q; //q个查询!
cin >> q;
while (q --)
{
int u, v;
cin >> u >> v;
if (dist[u][v] >= 0x3f3f3f3f) puts("Impossible");
else cout << dist[u][v] << ' ' << sum[u][v] << endl;
}
return 0;
}