1280: Emmy卖猪pigs

1280: Emmy卖猪pigs

Time Limit: 1 Sec   Memory Limit: 162 MB
Submit: 186   Solved: 126
[ Submit][ Status][ Discuss]

Description

Emmy在一个养猪场工作。这个养猪场有M个锁着的猪圈,但Emmy并没有钥匙。顾客会到养猪场来买猪,一个接着一个。每一位顾客都会有一些猪圈的钥匙,他们会将这些猪圈打开并买走固定数目的猪。 所有顾客有的钥匙和他们需要买猪的数量在事先都告诉了Emmy,于是Emmy要订一个计划,使得卖出去的猪最多。 买卖的过程是这样的:一个顾客前来,并打开所有他可以打开的猪圈。然后Emmy从这些猪圈里牵出固定数目的猪卖给顾客(最多只能和顾客需要数相等),并可以重新安排这些开着的猪圈中的猪。 每个猪圈可以存放任意数目的猪。 写一个程序,使得Emmy能够卖出去尽可能多的猪。

Input

第一行有两个整数:M和N,表示猪圈数和顾客数。 第二行有M个整数,表示每个猪圈初始时有多少猪。 接下来的N行按照前来的次序描述了每一个顾客,每行的格式如下: A K1 K2…KA B A表示该顾客拥有的钥匙数,K1...KA表示每个钥匙所对应的猪圈,B表示该顾客需要购买的猪的数目。

Output

仅包含一个整数,即最多能卖出去的猪的数目。

Sample Input

3 3
3 1 10
2 1 2 2
2 1 3 3
1 2 6

Sample Output

7

HINT

1 ≤ M ≤ 1000
1 ≤ N ≤ 100

Source

[ Submit][ Status][ Discuss]

考虑如何构造出一个人能从哪些猪圈买猪,对于第i个猪圈维护一个集合Si
Si的意义,是如果当前这个人的购买集合里面含有i,那么在Si里面的猪圈也可以对这个人产生贡献
维护的话,每次对于每个人的集合,集合里面的元素互相可以添加到对方的集合
考虑两个元素x,y,Sx可以添加到Sy,Sy可以添加到Sx,但是x不能添加到Sy中的任何一个元素
显然,这种关系是不满足传递性的
这样构建图,复杂度大概为O(n*m^2),不过数据没有这么强= =
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
 
const int maxn = 1202;
const int maxm = 2E5 + 2E3 + 20;
typedef long long LL;
const LL INF = 1E16;
 
struct E{
    int to; LL cap,flow; E(){}
    E(int to,LL cap,LL flow): to(to),cap(cap),flow(flow){}
}edgs[maxm];
 
int n,m,cnt,s,t,L[maxn],cur[maxn],stk[maxn],st[maxn],vis[maxn],vis2[maxn];
bool bo[maxn][maxn];
 
vector <int> v[maxn],G[maxn];
queue <int> Q;
 
void Add(int x,int y,LL cap)
{
    v[x].push_back(cnt); edgs[cnt++] = E(y,cap,0);
    v[y].push_back(cnt); edgs[cnt++] = E(x,0,0);
}
 
bool BFS()
{
    for (int i = s; i <= t; i++) L[i] = 0;
    L[s] = 1; Q.push(s);
    while (!Q.empty())
    {
        int k = Q.front(); Q.pop();
        for (int i = 0; i < v[k].size(); i++)
        {
            E e = edgs[v[k][i]];
            if (e.cap == e.flow || L[e.to]) continue;
            L[e.to] = L[k] + 1; Q.push(e.to);
        }
    }
    return L[t];
}
 
LL Dinic(int x,LL a)
{
    if (x == t) return a; LL flow = 0;
    for (int &i = cur[x]; i < v[x].size(); i++)
    {
        E &e = edgs[v[x][i]];
        if (e.cap == e.flow || L[e.to] != L[x] + 1) continue;
        LL f = Dinic(e.to,min(a,e.cap - e.flow));
        if (!f) continue; flow += f; e.flow += f;
        edgs[v[x][i]^1].flow -= f; a -= f;
        if (!a) return flow;
    }
    if (!flow) L[x] = -1; return flow;
}
 
LL getLL()
{
    char ch = getchar(); LL ret = 0;
    while (ch < '0' || '9' < ch) ch = getchar();
    while ('0' <= ch && ch <= '9')
        ret = ret * 10LL + 1LL * (ch - '0'),ch = getchar();
    return ret;
}
 
int main()
{
    #ifdef DMC
        freopen("DMC.txt","r",stdin);
    #endif
     
    m = getLL(); n = getLL(); t = m + n + 1;
    for (int i = 1; i <= m; i++) Add(i,t,getLL());
    for (int i = 1; i <= n; i++)
    {
        int k = getLL(),tp = 0;
        for (int j = 1; j <= k; j++)
        {
            int A; A = stk[j] = getLL();
            if (vis[A] != i) vis[A] = i,Add(i + m,A,INF);
            for (int l = 0; l < G[A].size(); l++)
            {
                int B = G[A][l];
                if (vis[B] != i) vis[B] = i,Add(i + m,B,INF);
                if (vis2[B] != i) vis2[B] = i,st[++tp] = B;
            }
        }
        Add(s,i + m,getLL()); if (!k) continue;
        for (int j = 1; j <= k; j++)
        {
            int A = stk[j];
            for (int l = j + 1; l <= k; l++)
            {
                int B = stk[l];
                if (!bo[A][B]) bo[A][B] = 1,G[A].push_back(B);
                if (!bo[B][A]) bo[B][A] = 1,G[B].push_back(A); 
            }
            for (int l = 1; l <= tp; l++)
                if (st[l] != A && !bo[A][st[l]])
                    bo[A][st[l]] = 1,G[A].push_back(st[l]);
        }
    }
     
    LL MaxFlow = 0;
    while (BFS())
    {
        for (int i = s; i <= t; i++) cur[i] = 0;
        MaxFlow += Dinic(s,INF);
    }
    cout << MaxFlow << endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值