zoj 2770 Burn the Linked Camp(火烧连营)

题意:陆逊已知刘备的每个大营最多能容纳Ci个士兵,并且可以估计到第i个大营到第j个大营至少有多少士兵,求刘备最少有多少个士兵。


分析:根据给出的数据我们可以得到一系列不等式组,考虑采用差分约束系统求解。以第一组测试数据解释差分约束系统及构造求解。

设三个军营的人数分别为A1,A2,A3,容量为C1,C2,C3,前n个军营的总人数为Sn,则可以列出以下不等式组。

⑴第i个大营到第j个大营士兵总数至少有k个。

S2 - S0 >= 1100  --->  S0 - S2 <= -1100

S3 - S1 >= 1300  --->  S1 - S3 <= -1300

⑵第i个大营到第j个大营不超过这些兵营容量只和,设d[i]为前i个大营容量总和。

S2 - S0 <= d[2] - d[0] = 3000

S3 - S1 <= d[3] - d[1] = 3000

⑶每个兵营实际人数不超过容量。

A1 <= 1000 ---> S1 - S0 <= 1000

A2 <= 2000 ---> S2 - S1 <= 2000

A3 <= 1000 ---> S3 - S2 <= 1000

⑷Ai>=0

S0 - S1 <= 0

S1 - S2 <= 0

S2 - S3 <= 0

把以上不等式组整理好后,我们就可以构造出一个有向图,构造好图后,我们要求的是 S3 - S0的最小值,即 S3 - S0 >= M  ---> S0 -  S3 <= -M,求S3到S0的最短路径,长度为-M,最终结果就是M。若无最短路径则输出Bad Estimations。

以上参考自:《图论算法理论、实现及应用》---北京大学出版社


第一道差分约束的题,做完还不是很明白 - -。


代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>

using namespace std;

const long long inf = 10000000000000LL;
const int maxn = 10005;


struct node{
	int v;
	long long w;
	
	node(int _v, long long _w){
		v = _v; w = _w; 
	}
};


int n,m;
int c[maxn]; //每个兵营的人数限制
long long d[maxn]; //前i个兵营的人数总和
vector<node> list[maxn];
long long dist[maxn];//for spfa
int cnt[maxn];	//判断负环 
bool inq[maxn];


bool input(){
	if(scanf("%d%d",&n,&m) == EOF) return false;
	for(int i = 1; i <= n; i++) scanf("%d",&c[i]);
	
	//求和 
	d[0] = 0;
	for(int i = 1; i <= n; i++) d[i] = d[i-1] + c[i];
	
	//clear
	for(int i = 0; i <= n; i++) list[i].clear();
	
	int u,v,w;
	for(int i = 0; i< m; i++){
		scanf("%d%d%d",&u,&v,&w);
		//情形1 
		list[v].push_back(node(u-1,-w));
		//情形2
		list[u-1].push_back(node(v,d[v]-d[u-1]));
	}
	
	
	for(int i = 1; i <= n; i++){
		//情形3
		list[i-1].push_back(node(i,c[i]));
		//情形4
		list[i].push_back(node(i-1,0));
	}
	return true;
}

bool spfa(int s){
	queue<int> q;
	for(int i = 0; i <= n; i++){
		dist[i] = inf;
		inq[i] = false;
		cnt[i] = 0;
	}
	
	dist[s] = 0;
	q.push(s);
	cnt[s]++;
	while(!q.empty()){
		int u = q.front(); q.pop(); inq[u] = false;
		if(cnt[u] >= n) return false;
		for(int i = 0; i < list[u].size(); i++){
			int v = list[u][i].v;
			long long w = list[u][i].w;
			if(dist[u] + w < dist[v]){
				dist[v] = dist[u] + w;
				if(!inq[v]){
					q.push(v); inq[v] = true; cnt[v]++;
				}
			}
		}
	}
	return true;
}

void solve(){
	if(spfa(n)){
		printf("%lld\n",-dist[0]);
	}
	else{
		printf("Bad Estimations\n");
	}
}

int main(){
	while(input()){
		solve();
	}
	return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值