HOJ 2634 How to earn more

来源:互联网 发布:端口被系统占用 编辑:程序博客网 时间:2024/06/14 11:10

【题目分析】

    这是一道最小割的应用题,首先从源点向每一个任务连一条容量为能获得的钱的边,然后把每一个需要雇的人向汇点连一条为Vi的边,最后把每一个任务向需要的人连一条容量为INF的边,然后跑一遍最大流,那么割掉(满流)的部分如果在左侧代表我不做这个任务,那么用所有任务的价值和前去最大流(不做的那一部分) ,就是最大的价值了。


因为HOJ崩了,无法提交,所以并没有测试。但是样例过了,应该没有什么问题了。有时间再测吧

【代码】

#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#include <cstring>using namespace std;const int INF=1000000;#define M1(a) memset(a,-1,sizeof a)#define M0(a) memset(a,0,sizeof a)#define F(i,j,k) for (int i=j;i<=k;++i)#define maxn 50010int sum=0,en=0,tt,u[maxn],v[maxn],h[maxn],ne[maxn],map[maxn],f[maxn],S,T;inline void add(int a,int b,int r){u[en]=a;v[en]=b;ne[en]=h[a];f[en]=r;h[a]=en++;u[en]=b;v[en]=a;ne[en]=h[b];f[en]=0;h[b]=en++;}inline bool tell(){memset(map,-1,sizeof map);int que[501];int head=0,tail=0;que[tail++]=S;map[S]=0;while (head<tail){int u=que[head++];for (int i=h[u];i!=-1;i=ne[i]){if (map[v[i]]==-1&&f[i]){map[v[i]]=map[u]+1;que[tail++]=v[i];}}}if (map[T]!=-1) return true;else return false;}inline int zeng (int k,int now){if (k==T) return now;int r=0;for (int i=h[k];i!=-1&&now>r;i=ne[i]){if (map[k]+1==map[v[i]]&&f[i]!=0){int t=zeng(v[i],min(now-r,f[i]));f[i]-=t;f[i^1]+=t;r+=t;}}if (!r) map[k]=-1;return r;}inline int dinic(){int r=0,t;while (tell()) while (t=zeng(S,INF)) r+=t;return r; }inline void reset(){M1(u);M1(v);M1(h);M1(ne);}inline void solve(){int n,m;scanf("%d%d",&n,&m);S=0;T=n+m+1;for (int i=1;i<=n;++i){int x;scanf("%d",&x);sum+=x;add(S,i,x);}for (int i=1;i<=m;++i){int x;scanf("%d",&x);add(i+n,T,x);}for (int i=1;i<=n;++i){int x;scanf("%d",&x);for (int j=1;j<=x;++j){int y;scanf("%d",&y);add(i,y+1+n,INF);}}cout<<sum-dinic();}int main(){scanf("%d",&tt);F(i,1,tt) {reset();solve();}}


0 0
原创粉丝点击