托米去购物(最大权闭合子图模型-最小割最大流)

题目描述 
此时的托米老师已经出任CEO,迎娶白富美,走向了人生巅峰!于是这个暑假,托米老师打算在北京一个偏僻的小农村里度过他的假期。
由于这里什么都没有,于是他去超市选了很多生活用品,更多的是吃的,然后推着堆满零食的购物车到柜台等待结账。
当然,我们都知道他的钱包里有很多钱。但是,作为一名为生活精打细算的男孩子,他更愿意使用其他支付方式如:饭券,礼券,不同类型的优惠券等。但是饭券只能用于购买食物,而礼券通常只限于某种类型的礼物。
现在给你托米购物车中物品的数量N和每件物品的价格。也会给出他钱包中的代金券数量M以及允许使用的信息 。
在为他的购物付款时,托米可能使用代金券的金额超过他所购物品的成本。也可以在多张代金券之间拆分商品的成本,并使用代金券支付多件商品。
请你计算托米需要为购物支付的额外现金的最小金额。
输入描述:
输入的第一行包含一个整数T,用于指定测试用例的数量。
每个测试用例前面都有一个空白行。
每个测试用例从包含两个正整数N(物品数量)和M(券数量)的行开始。
接下来一行包含N个数字,第i个数字表示托米购物车里第i件物品的价格。
接下来一行包含M个数字,第i个数字表示第i张券的金额。
接下来有M行,当中的第 i 行描述第 i 张卷可以买哪些商品。每行的第一个数字是 K,代表第 i 张卷可以为 K 件商品付款,接下来还有 K 个数,是这 K 件商品的编号
输出描述:
对于每个测试用例输出数字,表示托米需要支付多少现金。
示例1
输入
1
3 2
15 20 10
20 30
3 1 2 3
1 3
输出
15
备注:
T≤40 N≤200 M≤1200
满足M>200的数据保证只有一组
单个物品金额和单张优惠券金额≤10000


题目大概:

中文题目好理解。

思路:

这是最小割模型中的最大权闭合子图。直接按照模型的建边方法,连边。跑一边最大流就可以了。

复习一遍最大权闭合子图了。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std ;

#define RPEF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )

#define copy( a , x ) memcpy ( a , x , sizeof a )

typedef long long LL ;

const int MAXN = 1500 ;
const int MAXE = 1000000 ;
const int MAXQ = 1000000 ;
const LL INF = 1e15 ;

struct Edge {
    int v , n ;
    LL c ;
    Edge ( int var = 0 , LL cap = 0 , int next = 0 ) :
        v ( var ) , c ( cap ) , n ( next ) {}
} ;

struct netWork {
    Edge edge[MAXE] ;
    int adj[MAXN] , cntE ;
    int cur[MAXN] , d[MAXN] , num[MAXN] , pre[MAXN] ;
    bool vis[MAXN] ;
    int Q[MAXQ] , head , tail ;
    int s , t , nv ;
    LL flow ;

    void init () {
        cntE = 0 ;
        memset(adj,-1,sizeof(adj));
    }

    void addedge ( int u , int v , LL c , LL rc = 0 ) {
        edge[cntE] = Edge ( v ,  c , adj[u] ) ;
        adj[u] = cntE ++ ;
        edge[cntE] = Edge ( u , rc , adj[v] ) ;
        adj[v] = cntE ++ ;
    }

    void rev_Bfs () {
        memset(vis,0,sizeof(vis));
        memset(num,0,sizeof(num));
        d[t] = 0 ;
        vis[t] = 1 ;
        head = tail = 0 ;
        Q[tail ++] = t ;
        num[0] = 1 ;
        while ( head != tail ) {
            int u = Q[head ++] ;
            for ( int i = adj[u] ; ~i ; i = edge[i].n ) {
                int v = edge[i].v ;
                if ( vis[v] )
                    continue ;
                vis[v] = 1 ;
                d[v] = d[u] + 1 ;
                ++ num[d[v]] ;
                Q[tail ++] = v ;
            }
        }
    }

    LL ISAP () {
        copy ( cur , adj ) ;
        rev_Bfs () ;
        flow = 0 ;
        int i , u = pre[s] = s ;
        while ( d[s] < nv ) {
            if ( u == t ) {
                LL f = INF ;
                int pos ;
                for ( i = s ; i != t ; i = edge[cur[i]].v )
                    if ( f > edge[cur[i]].c )
                        f = edge[cur[i]].c , pos = i ;
                for ( i = s ; i != t ; i = edge[cur[i]].v )
                    edge[cur[i]].c -= f , edge[cur[i] ^ 1].c += f ;
                u = pos ;
                flow += f ;
            }
            for ( i = cur[u] ; ~i ; i = edge[i].n )
                if ( edge[i].c && d[u] == d[edge[i].v] + 1 )
                    break ;
            if ( ~i ) {
                cur[u] = i ;
                pre[edge[i].v] = u ;
                u = edge[i].v ;
            }
            else {
                if ( 0 == ( -- num[d[u]] ) )
                    break ;
                int mmin = nv ;
                for ( i = adj[u] ; ~i ; i = edge[i].n )
                    if ( edge[i].c && mmin > d[edge[i].v] )
                        cur[u] = i , mmin = d[edge[i].v] ;
                d[u] = mmin + 1 ;
                ++ num[d[u]] ;
                u = pre[u] ;
            }
        }
        return flow ;
    }
} ;

netWork net ;

int n,m;
int a[300];
int b[1300];
long long sum=0;
vector<int>G[1300];
void work () {
    int d , u , v , c ;
    net.init () ;
    net.s = 0 , net.t = n+m+1, net.nv = net.t + 1 ;

    for(int i=1;i<=n;i++)
    {
        net.addedge(net.s,i,a[i]);
    }
    for(int i=1;i<=m;i++)
    {
        net.addedge(n+i,net.t,b[i]);
    }
    for(int i=1;i<=m;i++)
    {
        for(int j=0;j<G[i].size();j++)
        {
            int v=G[i][j];
            net.addedge(v,n+i,INF);
        }
    }
    LL flow = net.ISAP () ;

    printf ( "%lld\n" ,  sum-flow) ;
}

int main () {
    int T ;
    scanf ( "%d" , &T ) ;
    while ( T -- ) {
        sum=0;
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)G[i].clear();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&b[i]);
        }
        for(int i=1;i<=m;i++)
        {
            int q;
            scanf("%d",&q);
            for(int j=1;j<=q;j++)
            {
                int u;
                scanf("%d",&u);
                G[i].push_back(u);
            }
        }
        work () ;
    }
    return 0 ;
}


猜你喜欢

转载自blog.csdn.net/a1046765624/article/details/80663326