LightOJ-1074

Extended Traffic

达卡市一天天变得拥挤而喧闹。某些道路总是拥堵。为了说服人们避免最短的路线,从而避免拥挤的道路到达目的地,市政府制定了一项新计划。城市的每个路口都标有正整数(≤20),表示路口的繁忙程度。每当有人从一个路口(源路口)到另一个路口(目的地路口)时,市政府都会从旅行者那里得到3(目的地的繁忙度-源的繁忙度)3(即差额的立方)。当局已任命您找出当某人从某个结点(零点)移到其他几个结点时可以赚取的最低总金额。

Input

输入以整数T(≤50)开头,表示测试用例的数量。
每种情况都包含一个空行和一个表示连接数的整数n(1 <n≤200)。下一行包含n个整数,分别表示结点从1到n的繁忙程度。下一行包含整数m,即城市中的道路数量。接下来的m条线中的每条线(每条道路一条)包含相应道路连接的两个交叉点编号(源,目的地)(所有道路都是单向的)。下一行包含整数q,即查询数。接下来的q行各包含一个目标结点编号。从一个路口到另一个路口最多只能有一条直接道路。

Output

对于每种情况,请在一行中打印案件编号。然后打印q行,每个查询一行,每行包含从交界点1(零点)到给定交界点时的最低总收入。但是,对于总收入少于3的查询,或者如果从零点无法到达目的地,请打印“?” 。

思路:
1.边权为(v-u)^3
2.存在负边权,用spfa
3.可能存在负环,记录边入队次数,当入队次数大于等于顶点数说明存在负环,需退出,否则会超时

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;

const int M = 50000, inf = 0x3f3f3f3f;
int n, a[205], m, q, u, v, p, len = 1, head[205], d[205], cnt[205];
bool vis[205];
struct edge{
	int v, next, w;
}e[M];

void add(int u, int v, int w) {
	e[len].v = v;
	e[len].w = w;
	e[len].next = head[u];
	head[u] = len++;
}

void spfa() {
	memset(d, 0x3f, sizeof(d));
	memset(vis, false, sizeof(vis));
	memset(cnt, 0, sizeof(cnt));
	d[1] = 0;
	queue<int> q;
	q.push(1);
	while(!q.empty()) {
		int u = q.front();
		q.pop();
	//	printf("---------%d\n", u);
		vis[u] = false;
		for(int j = head[u]; j; j = e[j].next) {
			int v = e[j].v;
			int w = d[u] + e[j].w;
			if(d[v] > w) {
				d[v] = w;
	//			printf("==%d, %d==\n", v, d[v]);
				cnt[v] = cnt[u] + 1;
				if(cnt[v] >= n) break;
				if(!vis[v]) {
	//				printf("**%d**\n", v);
					q.push(v);
					vis[v] = true;
				}
			}
		}
	} 
}

int main() {
	int t;
	scanf("%d", &t);
	for(int k = 1; k <= t; k++) {
		memset(head, 0, sizeof(head));
		len = 1;
		scanf("%d", &n);
		for(int i = 1; i <= n; i++) {
			scanf("%d", &a[i]);
		}
		scanf("%d", &m);
		while(m--) {
			scanf("%d%d", &u, &v);
			int w = (a[v] - a[u]) * (a[v] - a[u]) * (a[v] - a[u]);
			add(u, v, w);
		}
		scanf("%d", &q);
		printf("Case %d:\n", k);
		spfa();
		while(q--) {
			scanf("%d", &p);
			if(d[p] >= 3 && d[p] < inf)
				printf("%d\n", d[p]);
			else{
				printf("?\n");
			}
		}
	}
	return 0;
}
 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值