toj 1421 最大流sap

/*
题意:有N家公司和N家银行,这N家公司只会向N家银行借贷,N家银行也只借贷给N家公司,被pol**e查账,查出
N家公司分别借贷了SR[i],N家银行分别借出了SC[i],交易额限制在100以下(这个地方没看到,悲剧WA);求这
样的借贷是否合理,合理则输出合法交易的矩阵。

题解:最大流;
建图:加入源点,在源点和银行之间加入有向边,权值为该银行借出的金额,银行和公司之间分别加入权值为100
的有向边,每间银行都指向所有的公司,加入汇点,在所有公司和汇点之间加入有向边,权值为公司所借的金额
数,求出最大流,然后银行和公司之间的边的权值的变化即为所求解。遍历所有边一次记录到矩阵中。
*/
#include <iostream>
#include <cstring>

using namespace std;

#define EMAX 20500
#define VMAX 250

const int INF = 0xfffffff;

int head[VMAX],dis[VMAX],cur[VMAX],gap[VMAX],pre[VMAX];
int map[VMAX][VMAX];
int EN;
struct edge
{
    int from,to;
    int weight;
    int next;
}e[EMAX];

void insert(int u,int v,int w) 
{
    e[EN].from = u;
    e[EN].to = v;
    e[EN].weight = w;
    e[EN].next = head[u];    
    head[u] = EN++;
    e[EN].weight = 0;
    e[EN].from = v;
    e[EN].to = u;
    e[EN].next = head[v];    
    head[v] = EN++;
}

int sap(int s,int t, int n)//sap模版
{
    memset(dis,0,sizeof(dis));
    memset(gap,0,sizeof(gap));
    for(int i=0; i<=n; i++)
        cur[i] = head[i];
    int u = pre[s];
    pre[s] = s;
    int ret = 0;
    int temp = -1;
    gap[0] = n;
    bool flag;
    while(dis[s] < n)
    {
        flag = false;
        for(int &i = cur[u]; i != -1; i = e[i].next)
        {
            int v = e[i].to;
            if(e[i].weight && dis[u] == dis[v] + 1)
            {
                if (temp == -1 || temp>e[i].weight)
                    temp = e[i].weight;
                pre[v] = u;
                u = v;
                if(v == t)
                {
                    ret += temp;
                    for(u = pre[u];v != s;v = u,u = pre[u])
                    {
                        e[cur[u]].weight -= temp;
                        e[cur[u]^1].weight += temp;
                    }
                    temp = -1;
                }
                flag = true;
                break;
            }
        }
        if (flag)
            continue;

        int mindis = n;
        for(int i = head[u]; i != -1 ; i = e[i].next)
        {
            int v = e[i].to;
            if(e[i].weight && mindis > dis[v])
            {
                cur[u] = i;
                mindis = dis[v];
            }
        }
        gap[dis[u]]--;
        if( gap[dis[u]] == 0)
            break;
        dis[u] = mindis+1;
        gap[dis[u]]++;
        u = pre[u];
    }
    return ret;
}

int main(void)
{
    int n,t,sum;
    while (cin >> n)
    {
        sum = 0;
        memset(head,-1,sizeof(head));
        memset(map,0,sizeof(map));
        EN = 0;
        for(int i=1; i<=n; i++)
        {
            cin >> t;
            sum += t;
            insert(0,i,t);//源点连接
        }
        for(int i=1; i<=n; i++)
        {
            cin >> t;
            insert(n+i,2*n+1,t);//汇点连接
        }
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)//公司和银行连接
                insert(i,n+j,100);
        if (sum == sap(0,n+n+1,n+n+2))
        {
            cout << "YES" << endl;
            for(int u=1; u<=n; u++)//遍历所有边并且记录值
            {
                for(int i=head[u]; i!=-1; i=e[i].next)
                {
                    if (e[i].to != 0)
                    {
                        map[u][e[i].to-n] = e[i^1].weight;
                    }
                }
            }
            for(int i=1; i<=n; i++)
            {
                for(int j=1; j<=n; j++)
                {
                    if (j == 1)
                        cout << map[i][j];
                    else
                        cout << " " << map[i][j];
                }
                cout << endl;
            }
        }
        else
            cout << "NO" << endl;
    }
    return 0;
}

 

posted @ 2014-03-21 00:01  辛力啤  阅读(246)  评论(0编辑  收藏  举报