题意:
这一晚,TT 做了个美梦!
在梦中,TT 的愿望成真了,他成为了喵星的统领!喵星上有 N 个商业城市,编号 1 ~ N,其中 1 号城市是 TT 所在的城市,即首都。
喵星上共有 M 条有向道路供商业城市相互往来。但是随着喵星商业的日渐繁荣,有些道路变得非常拥挤。正在 TT 为之苦恼之时,他的魔法小猫咪提出了一个解决方案!TT 欣然接受并针对该方案颁布了一项新的政策。
具体政策如下:对每一个商业城市标记一个正整数,表示其繁荣程度,当每一只喵沿道路从一个商业城市走到另一个商业城市时,TT 都会收取它们(目的地繁荣程度 - 出发地繁荣程度)^ 3 的税。
TT 打算测试一下这项政策是否合理,因此他想知道从首都出发,走到其他城市至少要交多少的税,如果总金额小于 3 或者无法到达请悄咪咪地打出 ‘?’。
注意:多组数据,第i组数据第一行要输出Case i:。
思路:
求1到其他点的最短路,图中存在负权边,可能存在负环。所以只能用SPFA来求单源最短路径。
在SPFA中要判断负环是否存在:如果存在负环,那么最短路经过的边数会>=n,一些边被松弛的次数会>=n。也就是说到某一点的最短路的边数超过了n-1则说明有负环。用cnt[v]来记录到达v的最短路边数,若cnt[v]>=n则找到负环。
找到负环后需要将负环所在的连通块进行标记,在松弛时要跳过这些连通块里的顶点。使用dfs来进行标记,若顶点在负环所在连通块里,则fuhuan[v]=1。
总结:
一道SPFA的题目,需要对负环进行处理。输出有多组数据,且第i组数据要输出一行Case i:,就很容易忽略而WA。
代码:
#include <iostream>
#include <queue>
using namespace std;
int INF=1e8;
int n,m,q,p;
int a[201];
//链式前向星
struct edge
{
int to,next,w;
};
edge e[100010];
int head[201],tot;
void add(int x,int y,int w)
{
e[++tot].to=y,e[tot].next=head[x];
e[tot].w=w,head[x]=tot;
}
int dis[201],inq[201],cnt[201];
//inq为1在队列中;cnt用于判断是否存在负环
bool fuhuan[201]; //在负环所在连通块为1
queue <int> qu;
void dfs(int v) //用于标记负环所在连通块
{
fuhuan[v]=1;
for(int i=head[v];i!=0;i=e[i].next)
{
int next=e[i].to;
if(fuhuan[next]==0)
dfs(next);
}
}
void SPFA(int s)
{
for(int i=1;i<=n;i++)
dis[i]=INF,inq[i]=0,cnt[i]=0;
dis[s]=0,inq[s]=1;
qu.push(s);
while(!qu.empty())
{
int u=qu.front();
qu.pop();
inq[u]=0;
for(int i=head[u]; i!=0; i=e[i].next)
{
int v=e[i].to,w=e[i].w;
if(fuhuan[v]) continue;
if(dis[v]>dis[u]+w)
{
cnt[v]=cnt[u]+1;
if(cnt[v]>=n) //找到负环
{
dfs(v);
}
dis[v]=dis[u]+w;
if(!inq[v])
{
qu.push(v);
inq[v]=1;
}
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
int T;
cin>>T;
for(int sj=1;sj<=T;sj++)
{
//初始化
for(int i=1;i<=200;i++)
head[i]=0,fuhuan[i]=0;
tot=0;
//读入
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
cin>>m;
for(int i=0;i<m;i++)
{
int A,B;
cin>>A>>B;
int w=(a[B]-a[A])*(a[B]-a[A])*(a[B]-a[A]);
add(A,B,w);
}
//求距离
SPFA(1);
cin>>q;
cout<<"Case "<<sj<<":"<<endl;
for(int op=0;op<q;op++)
{
cin>>p;
//输出税费
if(dis[p]==INF||dis[p]<3||fuhuan[p]==1)
cout<<"?"<<endl;
else cout<<dis[p]<<endl;
}
}
}