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