题意
有n个节点,和m带权单向边,要求从第一个节点到其余所有边的最短路,若该最短路小于3,则输出?
思路
题目的意思非常好理解,但是这道题目很难处理的一点在于如果图中出现了负环,那么该负环上的点和所有与该负环连接的点的最短路都不存在,如何去找到这些负环和起联通点是这个题目的关键。我之前学习spfa只知道如何判断有无负环出现,但这个题目需要标记所有的负环相关点,这个我们可以利用bfs来做到,然而关于搜索负环也可以用bfs和dfs两种方法实现:
/*SPFA算法判断负环:
1. bfs 判断标准是若一个节点入队大于n次,则说明存在负环
2. dfs 判断标准是一个点在多个路径上出现,则说明存在负环
*/
#include <iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
using namespace std;
//DFS judge native circle
void DFS_SPFA(int u){
if(flag) return ;
vis[u]=true;
for(int i=head[u];i;i=edges[i].nxt){
if(flag) return ;
int v=edges[i].v;
if(d[u]+edges[i].t<d[v]){
d[v]=d[u]+edges[i].t;
if(vis[v]){
flag=true;
return ;
}else{
DFS_SPFA(v);
}
}
}
vis[u]=false;
}
void bfs(int x)
{
circle[x] = true;
for(int i=0; i<g[x].size(); i++)
{
int v = g[x][i].second;
if(!circle[v])
bfs(v);
}
}
//bfs judge native circle and mark all the relative node
void spfa_dfs(int start)
{
bool inque[maxn];
int inq_cnt[maxn];
for(int i=1; i<=n; i++)
d[i] = inf;
memset(inque, false, sizeof(inque));
memset(inq_cnt, 0, sizeof(inq_cnt));
queue <int> q;
q.push(start);
inq_cnt[start]++;
d[start] = 0;
while(!q.empty())
{
int u = q.front();
q.pop();
inque[u] = false;
for(int i=0; i<g[u].size(); i++)
{
int v = g[u][i].second;
if(circle[v])
continue;
int cost = g[u][i].first;
if(d[v] > d[u] + cost)
{
d[v] = d[u] + cost;
if(!inque[v])
{
q.push(v);
inque[v] = true;
inq_cnt[v]++;
if(inq_cnt[v] > n)
dfs(v);
}
}
}
}
}
搞清楚了这些,那么这个题目剩下的就很好解决了,但是还是有一个坑点,不知道为什么memset函数用起来出了错误,用memset函数给d数组赋极大值时,会使后面的判断出现错误,到现在我也不明白为什么。。。。
代码:
#include <iostream>
#include <cstdio>
#include <queue>
#include <utility>
#include <cmath>
#include <cstring>
#define inf 0x3f3f3f3f
#define OUT freopen("/home/jiengupxing/Documents/test.out", "w", stdout);
using namespace std;
const static int maxn = 210;
typedef long long ll;
typedef pair<ll, int> pii;
int n;
ll d[maxn];
ll bussi[maxn];
bool circle[maxn];
ll cube(int a, int b)
{
ll res = 1;
for(int i=1; i<=3; i++)
{
res *= (bussi[b] - bussi[a]);
}
return res;
}
vector<pii> g[maxn];
void dfs(int x)
{
circle[x] = true;
for(int i=0; i<g[x].size(); i++)
{
int v = g[x][i].second;
if(!circle[v])
dfs(v);
}
}
void spfa(int start)
{
bool inque[maxn];
int inq_cnt[maxn];
for(int i=1; i<=n; i++)
d[i] = inf;//这里一定要用一个for循环去给d数组赋值
memset(inque, false, sizeof(inque));
memset(inq_cnt, 0, sizeof(inq_cnt));
queue <int> q;
q.push(start);
inq_cnt[start]++;
d[start] = 0;
while(!q.empty())
{
int u = q.front();
q.pop();
inque[u] = false;
for(int i=0; i<g[u].size(); i++)
{
int v = g[u][i].second;
if(circle[v])
continue;
int cost = g[u][i].first;
if(d[v] > d[u] + cost)
{
d[v] = d[u] + cost;
if(!inque[v])
{
q.push(v);
inque[v] = true;
inq_cnt[v]++;
if(inq_cnt[v] > n)
dfs(v);
}
}
}
}
}
int main()
{
//OUT
int t;
int CASE = 0;
scanf("%d", &t);
while(t--)
{
CASE++;
scanf("%d", &n);
memset(circle, false, sizeof(circle));
for(int i=1; i<=n; i++)
{
g[i].clear();
}
for(int i=1; i<=n; i++)
{
scanf("%lld", &bussi[i]);
}
int m;
scanf("%d", &m);
for(int i=1; i<=m; i++)
{
int a, b;
scanf("%d %d", &a, &b);
int cost = cube(a, b);
g[a].push_back({cost, b});
}
spfa(1);
int q;
scanf("%d", &q);
printf("Case %d:\n", CASE);
while(q--)
{
int p;
scanf("%d", &p);
if(circle[p] || d[p] < 3 || d[p] == inf)
printf("?\n", d[p]);
else
printf("%d\n", d[p]);
}
}
return 0;
}