1. 程式人生 > >LightOJ-1074 Extended Traffic (最短路-Bellman_Ford存在負環)

LightOJ-1074 Extended Traffic (最短路-Bellman_Ford存在負環)

題目連結

題意:給出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]);
		}
	}
}