poj1275

建图规则:


注意,当约束条件是>=的时候,采用最长路。如果不想敲最长路(其实就在spfa里面改一个地方。。)的话,可以把他们都同时乘以-1即可了。

例如s[i-1]-s[i]>=-t[i] ==> s[i]-s[i-1]<=t[i] ==> add_edge(i,i-1,t[i])。

#include <iostream>
#include <queue>

using namespace std;

#define MAXN 25
#define inf 1 << 20

struct node {
	int to, w, next;
} edge[MAXN * 30];

int adj[MAXN], dis[MAXN], c[MAXN]; //adj->head, dis->distance, c->count of visited;
bool vis[MAXN]; //vis->visted
int cnt; //cnt->count of node(s)

int r[MAXN], t[MAXN];

void add_edge(int u, int v, int w) {
	edge[cnt].to = v;
	edge[cnt].w = w;
	edge[cnt].next = adj[u];
	adj[u] = cnt++;
}

void init() {
	cnt = 0;
	for (int i = 0; i < MAXN; i++) {
		adj[i] = -1, dis[i] = inf, vis[i] = false, c[i] = 0;
	}
	dis[0] = 0;
}

void build(int ans) {
	init();
	add_edge(0, 24, -ans);
	for (int i = 1; i < MAXN; i++) {
		add_edge(i - 1, i, 0);
		add_edge(i, i - 1, t[i]);
	}
	for (int j = 1; j < MAXN; j++) {
		int i = (j + 8) % 24;
		if (i > j) {
			add_edge(j, i, -r[i]);
		}
		else if (i < j) {
			add_edge(j, i, -r[i] + ans);
		}
	}
}

bool spfa(int ans) {
	queue <int> q;
	q.push(0);
	vis[0] = true;
	c[0] = 1;
	while (!q.empty()) {
		int p, t = q.front();
		q.pop();
		p = adj[t];
		vis[t] = false;
		while (p != -1) {
			if (dis[edge[p].to] > dis[t] + edge[p].w) {
				dis[edge[p].to] = dis[t] + edge[p].w;
				if (!vis[edge[p].to]) {
					vis[edge[p].to] = true;
					q.push(edge[p].to);
					c[edge[p].to]++;
					if (c[edge[p].to] > 24) {
						return false;
					}
				}
			}
			p = edge[p].next;
		}
	}
	if (dis[24] == -ans) return true;
	else return false;
}

int main() {
	int T;
	cin >> T;
	while (T--) {
		for (int i = 1; i <= 24; i++) {
			cin >> r[i];
			t[i] = 0;
		}
		int n;
		cin >> n;
		for (int i = 0; i < n; i++) {
			int temp;
			cin >> temp;
			t[temp + 1]++;
		}
		bool flag = true;
		for (int i = 0; i <= n; i++) { //0->super source
			build(i);
			if (spfa(i)) {
				cout << i << endl;
				flag = false;
				break;
			}
		}
		if (flag) {
			cout << "No Solution" << endl;
		}
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值