| ||||||||||
| Online Judge | Problem Set | Authors | Online Contests | User | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest | |||||||||
贴一个我觉得比较好的结题报告,贡路人参考!#include <iostream>
#define MAX_VAL 99999999 //最大值
#define MIN_VAL -99999999 //最小值
#define MAX_T 55
#define MAX_N 105
using namespace std;
int order[MAX_T][MAX_T]; //记录每个商店需要的各种商品的数量
int store[MAX_T][MAX_T]; //记录每个供货站存储的各种商品的数量
int graph[MAX_N][MAX_N]; //残留网络图
int goodsFlow[MAX_T]; //记录每中商品的总需求量
int cost[MAX_N][MAX_N][MAX_T]; //记录某个商店从某个供货站买某件商品需要的价格
int best[MAX_N]; //spfa或者bellmanford算法中维护的最小费用信息
int pre[MAX_N]; //spfa或者bellmanford算法中的记录增广路径
int queued[MAX_N + 1], head, tail; //spfa用到的队列
bool inQueue[MAX_N + 1]; //标记某个节点是否还在队列中
int minCost; //记录全局的总费用
int n, m, k; //输入的n, m, k变量信息
//每轮使用MCMF时需要调用此函数初始化建图
void initGraph(int goodId)
{
//初始化残留网络, 增加源点0和汇点n + m + 1
memset(graph, 0, sizeof(graph));
int i, j;
for(i = 1; i <= n; i++) //shop
{
//源点到每个商店的权值赋为这个商店对于当前商品的需求量
graph[0][i] = order[i][goodId];
for(j = n + 1; j <= n + m; j++) //store
{
//商店i与供货站j之间边的权值赋为商店i对于当前商品的需求量
graph[i][j] = order[i][goodId];
//供货站与汇点之间边的的权值赋为这个供货站对当前商品的库存量
graph[j][n + m + 1] = store[j - n][goodId];
}
}
}
//spfa算法
bool spfa(int goodId)
{
int i, j;
//初始化
for(i = 0; i <= m + n + 1; i++)
{
pre[i] = -1;
best[i] = MAX_VAL;
inQueue[i] = false;
}
//源点入队列
best[0] = 0;
queued[tail] = 0;
inQueue[0] = true;
tail = tail % MAX_N + 1;
//当队列不空则持续执行
while(head != tail) //当队列不空则持续执行
{
//弹出队首元素
i = queued[head];
head = head % MAX_N + 1;
inQueue[i] = false;
if(best[i] == MAX_VAL) continue;
//访问当前节点的邻居结点
for(j = 0; j <= m + n + 1; j++)
{
if(j == i) continue;
//关键点:松弛的条件是,残留网络中这条边还有剩余流量,这条边在cost费用数组中是存在的,且这样松弛可以更优
if(graph[i][j] > 0 && cost[i][j][goodId] != MIN_VAL && best[i] + cost[i][j][goodId] < best[j])
{
//松弛
best[j] = best[i] + cost[i][j][goodId];
pre[j] = i;
//被松弛点如果不在队列中则入队列
if(!inQueue[j]) {
queued[tail] = j;
tail = tail % MAX_N + 1;
inQueue[j] = true;
}
}
}
}
//如果汇点没有被松弛到,则说明已经不存在增广路径了
return best[n + m + 1] != MAX_VAL;
}
//这里原来使用了bellmanFord算法,后来改为spfa算法,发现效率差的并不多,看来这个不是关键
//其实这题也可以做成二分图的最优匹配,效率肯定会比MCMF高的,这个有时间再弄吧,呼呼
/*
bool bellManFord(int goodId)
{
int i, j;
for(i = 0; i <= m + n + 1; i++)
{
pre[i] = -1;
best[i] = MAX_VAL;
}
best[0] = 0;
bool con = true;
while(con)
{
con = false;
for(i = 0; i <= m + n + 1; i++)
{
if(best[i] == MAX_VAL) continue;
for(j = 0; j <= m + n + 1; j++)
{
if(graph[i][j] > 0 && cost[i][j][goodId] != MIN_VAL && best[i] + cost[i][j][goodId] < best[j])
{
best[j] = best[i] + cost[i][j][goodId];
pre[j] = i;
con = true;
}
}
}
}
return best[n + m + 1] != MAX_VAL;
}
*/
//MCMF的主函数,求买货物goodId,且总的需求量是totalFlow下是否可以存在一个最小代价的满足方案
bool maxFlowMinCost(int goodId, int totalFlow)
{
//建图
initGraph(goodId);
int totalCost = 0;
int flowCount = 0;
//能找打增广路径,则持续增流
while(spfa(goodId))
{
//取增广路径上的最小流量值
int minFlow = MAX_VAL, preNode, curNode = m + n + 1;
while((preNode = pre[curNode]) != -1)
{
if(graph[preNode][curNode] < minFlow)
minFlow = graph[preNode][curNode];
curNode = preNode;
}
//增加总的流量
flowCount += minFlow;
curNode = m + n + 1;
//增流操作
while((preNode = pre[curNode]) != -1)
{
//对残留网络的修改
graph[preNode][curNode] -= minFlow;
graph[curNode][preNode] += minFlow;
//对费用图的修改,这个很重要
cost[curNode][preNode][goodId] = - cost[preNode][curNode][goodId];
//计算增加这个流量所需的新费用
totalCost += minFlow * cost[preNode][curNode][goodId];
curNode = preNode;
}
}
minCost += totalCost;
//如果已经满足的总流量不等于总的需求流量,则不存在这样一个方案
return flowCount == totalFlow;
}
int main()
{
int i, j, t;
while(scanf("%d%d%d", &n, &m, &k) && (n + m + k) != 0) //n->商店,m->供货站,k->商品 供货站->商店
{
memset(goodsFlow, 0, sizeof(goodsFlow));
minCost = 0;
//输入每个商店需要的各种商品的数量
for(i = 1; i <= n; i++)
{
for(j = 1; j <= k; j++)
{
scanf("%d", &order[i][j]);
goodsFlow[j] += order[i][j];
}
}
//输入每个供货站存储的各种商品的数量
for(i = 1; i <= m; i++)
for(j = 1; j <= k; j++)
scanf("%d", &store[i][j]);
//建立费用图
for(i = 1; i <= k; i++) //goods
{
for(j = 0; j <= n + m + 1; j++) //shop
{
for(t = 0; t <= n + m + 1; t++) //store
{
//源点和商店之间的费用为0
if(j == 0 && t != 0 && t != n + m + 1) cost[j][t][i] = 0;
//供货站和商店之间的费用也为0
else if(j != 0 && j != n + m + 1 && t == n + m + 1) cost[j][t][i] = 0;
//用MIN_VAL标识不存在的边
else cost[j][t][i] = MIN_VAL;
//商店和供货站之间的费用为输入费用
if(j >= 1 && j <= n && t >= n + 1 && t <= n + m) scanf("%d", &cost[j][t][i]);
}
}
}
bool can = true;
//遍历所有商品看是否都能满足
for(i = 1; i <= k; i++)
{
//initGraph(i);
if(!maxFlowMinCost(i, goodsFlow[i]))
{
can = false;
break;
}
}
if(can) printf("%d\n", minCost);
else printf("-1\n");
}
return 0;
}
Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator