您的位置:首页 > 其它

2014年-12月 CCF-5 货物调度

2017-08-18 21:26 148 查看
题意:

某公司要处理一个周期性的物流问题。  有n个城市,第i个城市在每周的第j(1≤j≤7) 天会生产aij吨某种货物,同时需要消耗bij吨该种货物。已知每周的产量等于消耗量(即aij之和等于bij之和)。  城市之间有m条道路,第k条道路连接了城市sk和tk。一条道路上运输1吨货物有一个固定的成本ck。道路都可以双向使用。每天运输的货物量没有限制。城市之间的距离并不远,货物可以从任意一个城市运输到任意另一个城市并且在当天到达。  货物如果在当天没有被消耗掉,就需要存放在仓库里过夜。第i个城市的仓库容量为vi,存放1
吨货物过一夜所需的成本是wi。  请你计算该公司如果每周循环性地按照一个固定的流程调度货物的话,该公司在最优方案下每周需要为货物的运输和存储消耗多少成本。

思路: 一眼费用流。

模型建图:

对于每个点和他的仓库的每一天都建一个点。

aij - bij > 0 则 原点向该点连边,流量为aij-bij,费用为0。

aij - bij < 0 则该点向汇点连边,流量为bij -aij,费用为0。

对于每一天的生产点都按照给定的图建立双向变,流量inf,费用为运输费用。

对于每一天生产点向当天的仓库连一条边,流量为v,费用为w,然后仓库向下一天的能到达的生产点连边,容量为inf,费用为运输费用。 注意因为是一个周期问题,所以周7需要向周1连边。

代码:

#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <vector>
#include <cstdio>
#include <utility>
#include <cstring>
#include <iostream>
#include <algorithm>
const int maxn = 3007;
const int maxm = 300003;
const int inf = 0x3f3f3f3f;

int map[maxn][maxn];
int v[maxn], w[maxn];
int a[maxn][11], b[maxn][11];

int _flow_cur, _cost_cur;

struct Edge
{
int u, v, cap, cost, next;
Edge() {}
Edge(int u, int v, int cap, int cost, int next)
: u(u), v(v), cap(cap), cost(cost), next(next) {}
} edges[maxm];

int head[maxn], e_cnt;
bool visited[maxn];
int SLK[maxn], dist[maxn], _start_, _end_;

void init()
{
_flow_cur = _cost_cur = 0;
e_cnt = 0;
memset(head, -1, sizeof(head));
memset(visited, 0, sizeof(visited));
}

void add(int u, int v, int cap, int cost)
{
edges[e_cnt] = Edge(u, v, cap, cost, head[u]); head[u] = e_cnt ++;
edges[e_cnt] = Edge(v, u, 0 , -cost, head[v]); head[v] = e_cnt ++;
}

bool modlabel()
{
int delta = inf;
for(int i = 0; i <= _end_; i ++) {
if( !visited[i] && SLK[i] < delta ) {
delta = SLK[i];
SLK[i] = inf;
}
}
if(delta == inf) return false;
for(int i = 0; i <= _end_; i ++) {
if( visited[i] ) dist[i] += delta;
}
return true;
}

int aug(int u, int flow, int pre)
{
if( u == _end_ ) {
_cost_cur += flow * dist[_start_];
return flow;
}

visited[u] = true;
int flow_rest = flow;
for(int i = head[u]; ~i; i = edges[i].next) {
register int v = edges[i].v;
if( !visited[v] && edges[i].cap ) {
int temp = dist[v] + edges[i].cost - dist[u];
if( !temp ) {
int delta = aug( v, std::min(flow_rest, edges[i].cap), u );
if( delta > 0 ) {
flow_rest -= delta;
edges[i].cap -= delta;
edges[i^1].cap += delta;
}
if( flow_rest == 0 ) return flow;
} else {
if( temp < SLK[v] ) {
SLK[v] = temp;
}
}
}
}

return flow - flow_rest;
}

void cost_flow()
{
for(int i = 0; i <= _end_; i ++) {
dist[i] = 0;
SLK[i] = inf;
}
do {
int ret = 0;
do {
_flow_cur += ret;
memset(visited, 0, sizeof(visited));
ret = aug(_start_, inf, -1);
} while( ret );
} while( modlabel() );
}

int main()
{
int n, m;
while(~scanf("%d %d", &n, &m)){
init();
for(int i = 1; i <= n; i ++) {
for(int j = 0; j <= 6; j ++) {
scanf("%d", &a[i][j]);
}
for(int j = 0; j <= 6; j ++) {
scanf("%d", &b[i][j]);
}
scanf("%d %d", &v[i], &w[i]);
}
memset(map, 0, sizeof(map));
for(int i = 0 ; i < m; i ++) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
map[u][v] = map[v][u] = w;
}
int _st = 0, _ed = 14*n+1;
_start_ = _st, _end_ = _ed;
for(int i = 0; i <= 6; i ++) {
for(int j = 1; j <= n; j ++) {
int id_b = i * n; // 生产点base
int id_c = (i + 7) * n; // 仓库点base
if(a[j][i] > b[j][i]) add(_st, id_b+j, a[j][i]-b[j][i], 0);
if(a[j][i] < b[j][i]) add(id_b+j, _ed, b[j][i]-a[j][i], 0);
add(id_b+j, id_c+j, v[j], w[j]);
int nxt = ((i + 1) % 7) * n; // 下一天的生产点base
add(id_c+j, nxt+j, inf, 0);
for(int k = 1; k <= n; k ++) {
if(!map[j][k]) continue;
add(id_b+j, id_b+k, inf, map[j][k]);
add(id_c+j, nxt+k, inf, map[j][k]);
}
}
}
cost_flow();
printf("%d\n", _cost_cur);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: