题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=973
题目大意:给你n种武功,每两种武功都可以相互转化,但是有转化率f, 每次必须从一开始转化, 中间有武功转化不了, 后面的就不能在转化了, 问你能否可以无限增加转化。
在做这道题以前做了和这道题一样的一道题, 所以我认为很快就能AC了, 但是这道题我还是弄了一天还是没能AC。来讲一下让我很是郁闷的问题吧。 这道题可以用最短路判环(spfa只需稍微变一下)来做,也可以用直接深搜来做。我的最初想法就是深搜来做。我上一道题就是用深搜做的,我就开始写了, 然后就是各种WA, 后来搞到后台数据找到一组错误的输出, 然后就是各种改, 最终还是WA, 没办法了, 我就写了一个spfa, 然后就AC了, 看来正解还是spfa, 现在我还是不明白我以前的为什么错。所以发个博客记录一下, 以免在出现这种情况。同时想让路过的大牛给解释一下。
下面是代码
AC的
#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 500 + 10;
struct Edge
{
int v;
double f;
Edge(int i, double j) : v(i), f(j) {}
};
vector<Edge> G[maxn];
double d[maxn];
int cnt[maxn];
bool inq[maxn];
bool spfa(int s, int n)
{
queue<int> Q;
memset(inq, false, sizeof(inq));
memset(d, 0, sizeof(d));
memset(cnt, 0, sizeof(cnt));
d[s] = 1.0;
inq[s] = true;
Q.push(s);
while(!Q.empty())
{
int u = Q.front();
Q.pop();
inq[u] = false;
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i].v;
double ff = G[u][i].f;
if(d[v]<d[u]*ff)
{
d[v] = d[u]*ff;
if(!inq[v])
{
Q.push(v);
inq[v] = true;
if(++cnt[v] >= n)
return true;
}
}
}
}
return false;
}
int main()
{
int T, n, m, a, b;
double ff;
// freopen("Input.txt", "r", stdin);
// freopen("O.txt", "w", stdout);
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
for(int i = 0; i <= n; i++)
G[i].clear();
while(m--)
{
scanf("%d%lf%d", &a, &ff, &b);
G[a].push_back(Edge(b, ff));
}
if(spfa(1, n))
puts("Yes");
else
puts("No");
}
return 0;
}
WA的
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 500 + 10;
int vis[maxn];
int pre[maxn];
struct Info
{
int to;
double f;
Info(int i, double j) :to(i), f(j) {}
};
vector<Info> G[maxn];
bool dfs(int rt, int u, double ans)
{
vis[u] = -1;
for(int i = 0; i < G[u].size(); i++)
{
Info x = G[u][i];
int v = x.to;
pre[v] = pre[u];
double Ans = ans * x.f;
if(Ans == 0)
continue;
if(v==rt)
{
if(Ans>1.0)
return true;
}
if(!vis[v] && dfs(rt, v, Ans))
return true;
}
vis[u] = 1;
return false;
}
int main()
{
int T, n, m;
// freopen("Input.txt", "r", stdin);
// freopen("O.txt", "w", stdout);
scanf("%d", &T);
while(T--)
{
memset(pre, -1, sizeof(pre));
scanf("%d%d", &n, &m);
for(int i = 0; i <= n; i++)
G[i].clear();
while(m--)
{
int a, b;
double ff;
scanf("%d%lf%d", &a, &ff, &b);
G[a].push_back(Info(b, ff));
}
bool flag = false;
pre[1] = 1;
for(int i = 1; i <= n; i++)
{
memset(vis, 0, sizeof(vis));
if(pre[i]==1 && dfs(i, i, 1.0))
{
flag = true;
break;
}
}
if(flag)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
这是深搜的wa的代码,唯一一组出现错误测试数据
33肿武功, 93种转化 应该输出Yes 如果直接暴搜就会超时
33 93
30 0.3 32
23 0.9 6
18 0.9 21
13 0.9 14
21 1.2 11
28 0 24
32 0.5 29
23 1.1 12
26 0.5 8
7 0.1 12
6 1.4 33
29 0.9 30
12 1.3 6
10 0.4 32
33 0.2 6
9 0.5 12
24 1.7 22
4 1 11
3 0.5 1
1 0.8 2
20 0 7
5 1.7 15
13 1.1 16
7 0.7 21
30 0.6 31
18 0.9 10
28 1.7 14
31 0.8 33
27 1.6 15
29 0.4 19
26 0.9 2
23 0.8 5
20 0.4 6
29 1 7
11 1.6 31
30 0.6 17
18 1.5 23
21 1.2 32
21 0.4 16
6 0.3 20
13 0 33
7 0.3 32
14 0.2 4
7 0.3 28
14 0.7 9
17 0.9 28
1 0.1 19
3 0.9 7
11 0.8 29
33 1.9 10
9 0.7 13
7 0.3 17
5 0.1 21
18 0 16
9 1.7 5
11 0.7 10
20 1.2 14
13 0.5 22
29 0.3 23
12 0 21
1 0.1 16
29 1.3 25
1 0.7 29
6 0.9 25
4 0.3 8
27 1.5 14
11 0.5 17
4 1.8 33
32 1.4 26
11 0.2 32
30 0.2 7
29 1.6 5
18 0.2 6
8 0.4 28
23 1.8 33
17 1.3 23
16 0.5 13
22 0.3 26
25 0.7 22
2 1.6 32
16 1.6 26
33 1.8 8
19 0.2 29
28 0.5 13
23 1.8 24
8 0.7 5
19 1.1 23
27 0.9 5
16 0.7 22
19 1.3 9
28 1.9 26
31 0.8 6
25 1 16