题意不再赘述。首先建图。我们将一个点周围的点都给兑换成这个点,然后选择最大的值作为这个点的价值,然后这样不断的计算下去,直到计算到初始点,如果我们重新计算的价值大于初始点的值,就表明有兑换漏洞。这个过程看起来是不是很像求最短路呢?只不过我们把更新公式d[v] = min(d[v], d[u] + w[u][v])换成了d[v] = max(d[v], d[u]*w[u][v]),并且d[v]的含义也发生了变化,原来的d表示从初始点到v的最短距离,现在的d[v]表示从价值为1的初始点开始兑换,兑换到v这个点我们能够获得的最大价值。思路相似,我们套用最短路模板,但是我们求得并不是最短路。因为汇率可能小于1,即权值为负。不能用dijkstra。我们使用spfa或者floyd。
具体思路就是从源点src开始套用最短路模板不断的更新,更新结束后我们看一下d[src][src](从价值为1的初始点开始兑换,经历一系列过程再次兑换成初始点所能获得的最大价值)是不是大于初始值,如果大于,就输出yes。
因为对每个点都要spfa,所以我们也可以选择floyd。状态转移公式也变成了d[i][j] = max(d[i][j], d[i][k] * d[k][j])(注意d[i][j]是我们假设初始值是1,得到的答案。如果初始值为a,就要相应的乘以a倍。这也是状态转移公式用乘号的原因)。
spfa代码:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
using namespace std;
const int maxn = 1005;
double G[maxn][maxn];
int n, m;
bool spfa(int src){
int Inqueue[maxn];
double d[maxn];
memset(Inqueue, 0, sizeof(Inqueue));
memset(d, 0, sizeof(d));
queue<int> Q;
Q.push(src);
Inqueue[src] = 1;
d[src] = 1.0;
while (!Q.empty()){
int u = Q.front();
Q.pop();
Inqueue[u] = 0;
for (int v = 1; v <= n; v++){
if (G[u][v]){
double cost = G[u][v];
if (d[v] < d[u] * cost){
d[v] = d[u] * cost;
if (!Inqueue[v]){
Q.push(v);
Inqueue[v] = 1;
}
if (d[src] > 1.0) return true;
}
}
}
}
return false;
}
int main()
{
//freopen("1.txt", "r", stdin);
int Case = 1;
while (~scanf("%d", &n) && n){
map<string, int> msi;
char name[50];
for (int i = 1; i <= n; i++){
scanf("%s", name);
msi[name] = i;
}
scanf("%d", &m);
char u[50], v[50];
double cost;
memset(G, 0, sizeof(G));
for (int i = 0; i < m; i++){
scanf("%s%lf%s", u, &cost, v);
int uu = msi[u], vv = msi[v];
G[uu][vv] = cost;
}
printf("Case %d: ", Case++);
int ok = 0;
for (int i = 1; i <= n; i++){
if (spfa(i)){
ok = 1;
break;
}
}
if (ok) printf("Yes\n");
else printf("No\n");
}
return 0;
}
floyd代码:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
using namespace std;
const int maxn = 1005;
int n, m;
double d[maxn][maxn];
void Init(){
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++){
if (i == j) d[i][j] = 1;
else d[i][j] = 0;
}
}
void floyd(){
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++){
if (d[i][j] < d[i][k] * d[k][j])
d[i][j] = d[i][k] * d[k][j];
}
}
int main()
{
//freopen("1.txt", "r", stdin);
int Case = 1;
while (~scanf("%d", &n) && n){
map<string, int> msi;
char name[50];
for (int i = 1; i <= n; i++){
scanf("%s", name);
msi[name] = i;
}
scanf("%d", &m);
Init();
char u[50], v[50];
double cost;
for (int i = 1; i <= m; i++){
scanf("%s%lf%s", u, &cost, v);
int uu = msi[u], vv = msi[v];
d[uu][vv] = cost;
}
floyd();
printf("Case %d: ", Case++);
int i;
for (i = 1; i <= n; i++){
if (d[i][i] > 1){
printf("Yes\n");
break;
}
}
if (i == n + 1) printf("No\n");
}
return 0;
}