poj1149迈克卖猪问题(PIGS)

/**
建图:
<1>: 将顾客看作是除源点和汇点的结点,并且另设两个结点,源点和汇点
<2>:源点和每个猪圈的第一位顾客连边,边的权值是开始时猪圈中猪的数量
<3>:若源点和某个结点有重边,则将权值合并(因此,从原点流出的流量就是所有猪圈所能提供猪的数量)
<4>:顾客j紧跟顾客i打开某个猪圈,则置<i, j>的权值为无穷大,因为顾客j紧跟顾客i之后,迈克可以根据顾客j的需求,调来足够多的猪。
<5>:每个顾客都和汇点连接,边的权值即是每个顾客所希望买的猪的数目(最后流入汇点的流量即是迈克所能卖出猪的数量)


*/


#include <iostream>
#include <cstring>


using namespace std;


const int MAXN = 110;
const int MAXM = 1010;
const int INF = 100000000;


struct ArcType
{
    int c, f;
};


ArcType Edge[MAXN][MAXN];


int n;


int MIN(int a, int b)
{
    return a < b ? a : b;
}


int fabs(int a)
{
    return a < 0 ? (-a) : a;
}




void Ford()
{
    int pre[MAXN];
    int alpha[MAXN];
    int flag[MAXN];
    int que[MAXN];
    int qs, qe;
    while(1)
    {
        memset(pre, 0xff, sizeof(pre));
        memset(flag, 0xff, sizeof(flag));
        memset(que, 0, sizeof(que));
        memset(alpha, 0, sizeof(alpha));
        qs = qe = 0;
        que[qe++] = 0;
        flag[0] = 0, alpha[0] = INF, pre[0] = 0;
        while(qs < qe && (flag[n+1] == -1))
        {
            int u = que[qs++];
            for(int v = 1; v < n+2; ++v)
            {
                if(flag[v] == -1)
                {
                    if(Edge[u][v].c < INF && Edge[u][v].f < Edge[u][v].c)
                    {
                        flag[v] = 0;
                        pre[v] = u;
                        alpha[v] = MIN(alpha[u], Edge[u][v].c - Edge[u][v].f);
                        que[qe++] = v;
                    }
                    else if(Edge[v][u].c < INF && Edge[v][u].f > 0)
                    {
                        flag[v] = 0;
                        pre[v] = -u;
                        alpha[v] = MIN(alpha[u], Edge[v][u].f);
                        que[qe++] = v;
                    }
                }
            }
            flag[u] = 1;
        }


        if(flag[n+1] == -1 || alpha[n+1] == 0)
            break;
        int k1 = n+1;
        int k2 = fabs( pre[k1] );
        int a = alpha[n+1];
        while(1)
        {
            if(Edge[k2][k1].c < INF)
                Edge[k2][k1].f += a;
            else if(Edge[k1][k2].f > 0 && Edge[k1][k2].f < INF)
                Edge[k1][k2].f -= a;
            if(k2 == 0)
                break;
            k1 = k2;
            k2 = fabs( pre[k1] );
        }
    }
    int Maxflow = 0;
    for(int i = 1; i < n+1; ++i)
        if(Edge[0][i].c < INF)
            Maxflow += Edge[0][i].f;
    cout<<Maxflow<<endl;
}




void Inite()
{
    int m, k;
    cin>>m>>n;


    for(int i = 0; i < MAXN; ++i)
        for(int j = 0; j < MAXN; ++j)
            Edge[i][j].c = Edge[i][j].f = INF;
    int house[MAXM];
    int last[MAXM];
    memset(house, 0, sizeof(house));
    memset(last, 0, sizeof(last));
    for(int i = 1; i <= m; ++i)
        cin>>house[i];
    for(int i = 1; i <= n; ++i)
    {
        int num;
        cin>>num;
        for(int j = 0; j < num; ++j)
        {
            cin>>k;
            if(last[k] == 0)
            {
                if(Edge[0][i].c == INF)
                    Edge[0][i].c = house[k];
                else
                    Edge[0][i].c += house[k];
                Edge[0][i].f = 0;//初始时该边的实际流量定义为零流
            }
            else
            {
                Edge[ last[k] ][i].c = INF - 1;//保证last[k]买过之后,可以调来足够多的猪供顾客i购买,这个值虽定义的是无穷但是要比无穷小
                Edge[ last[k] ][i].f = 0;//因为该边存在,不存在定义的是两点之间是无穷
            }
            last[k] = i;
        }
        cin>>Edge[i][n+1].c;
        Edge[i][n+1].f = 0;
    }
/**
    for(int i = 0; i <= n+1; ++i)
    {
        for(int j = 0; j <= n+1; ++j)
        {
            if(Edge[i][j].c < INF)
                cout<<i<<" -> "<<j<<" : "<<Edge[i][j].c<<endl;
        }
    }
*/
}


int main()
{
    Inite();
    Ford();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值