列表

详情


NC16408. 托米去购物

描述

此时的托米老师已经出任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

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 27ms, 内存消耗: 2424K, 提交时间: 2018-06-01 20:08:28

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1580;
const int M=5e5+88;
const int INF=0x3f3f3f3f;
int head[N],tot,S,T;
int q[N],dis[N],n,m;
bool vis[N];
struct node
{
    int next,v,w;
} e[M<<2];
void add(int u,int v,int w)
{
    e[tot].v=v;
    e[tot].w=w;
    e[tot].next=head[u];
    head[u]=tot++;
}
bool bfs()
{
    memset(dis,-1,sizeof(dis));
    dis[S]=0;
    int l=0,r=0;
    q[r++]=S;
    while(l<r)
    {
        int u=q[l++];
        for(int i=head[u]; ~i; i=e[i].next)
        {
            int v=e[i].v;
            if(dis[v]==-1&&e[i].w>0)
            {
                q[r++]=v;
                dis[v]=dis[u]+1;
                if(v==T) return true;
            }
        }
    }
    return false;
}
int dfs(int s,int low)
{
    if(s==T||!low) return low;
    int ans=low,a;
    for(int i=head[s]; ~i; i=e[i].next)
    {
        if(e[i].w>0&&dis[e[i].v]==dis[s]+1&&(a=dfs(e[i].v,min(e[i].w,ans))))
        {
            e[i].w-=a;
            e[i^1].w+=a;
            ans-=a;
            if(!ans) return low;
        }
    }
    if(low==ans) dis[s]=-1;
    return low-ans;
}
int vt[1250];
int main()
{
	int Ta;
	for(scanf("%d",&Ta);Ta--;){
    scanf("%d%d",&n,&m);
    S=0,T=n+m+1;
    int x,y,ans=0;
    memset(head,-1,sizeof(head));
    tot=0;
    for(int i=1; i<=n; ++i)
    {
        scanf("%d",&x);
        add(i,T,x),add(T,i,0);ans+=x;
    }
    for(int i=1;i<=m;++i) scanf("%d",vt+i);
    for(int i=1;i<=m;++i) add(S,n+i,vt[i]),add(n+i,S,0);
    for(int i=1;i<=m;++i) {
    	for(scanf("%d",&y);y--;){
    		scanf("%d",&x);
    		add(n+i,x,vt[i]);
    		add(x,n+i,0);
		}
	}
    while(bfs()) ans-=dfs(S,INF);
    printf("%d\n",ans);
    }
}

C++(clang++11) 解法, 执行用时: 12ms, 内存消耗: 2808K, 提交时间: 2021-04-14 16:05:28

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
#define For(i,l,r) for(int i=l;i<=r;i++)
#define FOR(i,u) for(int i=now[u];i;i=nxt[i])
#define INF 0x3fffffff
#define MAXN 1501
#define MAXM 1000001
int T,N,M,s,t,fst[MAXN],now[MAXN],cnt=1,to[MAXM],flow[MAXM],nxt[MAXM],dep[MAXN];
int get(){int x=0;char c=getchar();while(c<'0'||c>'9')c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return x;}
void add(int u,int v,int f){to[++cnt]=v,flow[cnt]=f,nxt[cnt]=fst[u],fst[u]=cnt;to[++cnt]=u,flow[cnt]=0,nxt[cnt]=fst[v],fst[v]=cnt;}
bool bfs()
{
	memset(dep,-1,sizeof(dep));dep[s]=0;queue<int>q;q.push(s);
	while(!q.empty()){int u=q.front();q.pop();if(u==t)return 1;now[u]=fst[u];FOR(i,u)if(flow[i]&&dep[to[i]]==-1)dep[to[i]]=dep[u]+1,q.push(to[i]);}return 0;
}
int dfs(int u,int in)
{
	if(u==t||!in)return in;int ans=0;
	FOR(i,u){now[u]=i;if(dep[to[i]]!=dep[u]+1)continue;int tmp=dfs(to[i],min(in,flow[i]));in-=tmp,ans+=tmp,flow[i]-=tmp,flow[i^1]+=tmp;if(!in)break;}return ans;
}
int main()
{
	cin>>T;
	while(T--)
	{
		cin>>N>>M;s=0,t=N+M+1;memset(fst,0,sizeof(fst));cnt=1;int ans=0;For(i,1,N){int x=get();ans+=x;add(s,i,x);}For(i,1,M)add(i+N,t,get());
		For(i,1,M){int K=get();while(K--)add(get(),i+N,10000);}while(bfs())ans-=dfs(s,INF);cout<<ans<<endl;
	}
	return 0;
}

上一题