题意:给出t组样例,每组给出一个n,表示n个点,给出n-1组数据a[]表示每2~n地点上的人流量,下面给出m条路,路的权值为人流公式(a[i]-a[j])^3,故存在负环的情况,题目再给出一个q表示q次询问,询问起点1到x点的最短距离.
题解:不能用Dijsktra,只能用Bellman_Ford解决带负权问题,且它们之间若存在负环或者dis[x]<3 输出?其余输出dis[a].
代码如下:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int maxn = 500;
struct edge
{
int u, v, w;
edge() {}
edge(int uu, int vv, int ww) :u(uu), v(vv), w(ww) {}
};
vector<edge> e;
int dis[maxn], n;
bool vis[maxn], flag[maxn];
int a[maxn];
void Bellman_Ford()
{
vis[1] = true;
for (int k = 1; k<n; k++) //n-1次松弛
for (int i = 0; i<e.size(); i++)
{
edge &p = e[i];
if (vis[p.u] && ((!vis[p.v]) || (dis[p.u] + p.w<dis[p.v])))
{
vis[p.v] = true;
dis[p.v] = dis[p.u] + p.w;
}
}
for (int i = 0; i<e.size(); i++)
{
edge &p = e[i];
if (vis[p.u] && ((!vis[p.v]) || (dis[p.u] + p.w<dis[p.v]))) //判断该点是否还能进行松弛,能-》存在负环
flag[p.v] = true;
}
}
void init()
{
e.clear();
memset(vis, 0, sizeof(vis));
memset(flag, 0, sizeof(flag));
memset(dis, 0, sizeof(dis));
}
int main()
{
int t, m, cas = 1;
scanf("%d", &t);
while (t--)
{
init();
printf("Case %d:\n", cas++);
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
scanf("%d", &m);
while (m--) //m条有向边
{
int u, v;
scanf("%d%d", &u, &v);
e.push_back(edge(u, v, (a[v] - a[u])*(a[v] - a[u])*(a[v] - a[u]))); //题目公式
}
Bellman_Ford();
scanf("%d", &m);
while (m--)
{
int p;
scanf("%d", &p);
if (flag[p] || dis[p]<3)printf("?\n");
else printf("%d\n", dis[p]);
}
}
}