Online JudgeProblem SetAuthorsOnline ContestsUser
Web Board
Home Page
F.A.Qs
Statistical Charts
Problems
Submit Problem
Online Status
Prob.ID:
Register
Update your info
Authors ranklist
Current Contest
Past Contests
Scheduled Contests
Award Contest
User ID:
Password:
  Register

贴一个我觉得比较好的结题报告,贡路人参考!

Posted by nothing828 at 2010-08-19 17:48:13 on Problem 2516 and last updated at 2010-08-19 19:48:04
#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:
User ID:
Password:
Title:

Content:

Home Page   Go Back  To top


All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator