jzoj 4718. 【GDOI2017模拟7.20】准备食物2 费用流

来源:互联网 发布:windows中的用户账户 编辑:程序博客网 时间:2024/05/17 01:22

Description

古明地觉拥有的第三只眼,可以读取别人的内心想法,于是无论是妖怪,还是怨灵都为之感到恐惧,因此觉被人厌恶。
然而,觉却因能读心而深受那些无法开口的动物喜爱。整个地灵殿到处都是她的宠物(如火焰猫、地狱鸦)。
宠物多了,准备食物是个麻烦的问题。现在觉有m种食物,第i种食物有a[i]份。觉要为n个宠物按编号顺序分配食物,每个宠物需要1份食物。
觉通过读心,得出了每个宠物吃了每种食物后的喜悦值。觉还发现,对于一些宠物,假设它的编号为i,如果在它之前分配到食物的宠物中,超过s[i]个被分配了第num[i]种食物,那么它会密谋一些反动的事情(像间歇泉异变之类的)。
觉不允许反动的事情发生,也希望所有宠物获得的喜悦值最大,以让它们更好地为她管理地灵殿和灼热地狱的事务。现在她想知道,在不会反动的情况下,能获得的最大喜悦值为多少。如果无论怎样分配都会出现反动,或者食物不够分配,只要输出“Warning!”(不含引号)

Input

第一行一个整数T,表示数据组数。
对于每组数据,第一行两个正整数n,m。接下来n行,每行m个非负整数。第i行第j个v[i][j]表示宠物i分配了第j种食物后获得的喜悦值。接下来n行,每行两个整数s[i],num[i],如题目所示。如果s[i]=num[i]=-1,则表示第i个宠物无论如何都不会反动。最后一行m个非负整数,表示数组a(每种食物的份数)。

Output

 对于每组数据,一行一个输出答案。

Sample Input

23 34 5 39 2 13 5 5-1 -1-1 -10 12 2 22 1100009999-1 -10 12

Sample Output

12Warning!

Data Constraint

20%:n,m≤8
另有30%:所有s[i],num[i]均为-1
100%:1≤T≤5,1≤a[i],n≤200  1≤m≤100  -1≤s[i]≤n  -1≤num[i]≤m且num[i]≠0 0≤v[i][j]≤100000

分析:如果没有s和num这个限制的话就是一个很简单的费用流了。

源点向每只宠物连一条流量为1费用为0的边,每只宠物向每种食物连一条流量为1费用为喜悦值的边,每种食物向汇点连一条流量为食物数量费用为0的边然后跑一遍最大费用最大流就好了。

对于限制,我们可以进行如下处理:

对于一个限制s[i]和num[i],设食物num[i]的原来数量为sum,我们可以把原来num的点拆成两个,第一个点连向汇点的边流量是sum-s[i],且只有编号不小于i的宠物可以连到该点;第二个点连向汇点的边流量是s[i],且把所有的宠物都向该点连边。

然后对其他限制也做该处理,再跑一遍最大费用最大流就是答案鸟。


代码(非常不优美,建议别看):

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<queue>#define inf 0x7fffffff#define N 600using namespace std;int n,m,last[N],ls[N],a[N],sum[N],num[N],hap[N][N],dis[N],pre[N],vis[N],cnt,ansf,ans,tot,s,t,nx[N],fuck[300],v[300];struct edge{int from,to,op,c,w,next;}e[300005];queue <int> q;void insert(int u,int v,int c,int w){e[++cnt].from=u;e[cnt].to=v;e[cnt].op=cnt+1;e[cnt].c=c;e[cnt].w=w;e[cnt].next=last[u];last[u]=cnt;e[++cnt].from=v;e[cnt].to=u;e[cnt].op=cnt-1;e[cnt].c=0;e[cnt].w=-w;e[cnt].next=last[v];last[v]=cnt;}bool bfs(){for (int i=s;i<=t;i++){vis[i]=pre[i]=0;dis[i]=-inf/3;}dis[s]=0;while (!q.empty()) q.pop();q.push(s);vis[s]=1;while (!q.empty()){int u=q.front();q.pop();for (int i=last[u];i;i=e[i].next)if (e[i].c&&dis[u]+e[i].w>dis[e[i].to]){dis[e[i].to]=dis[u]+e[i].w;pre[e[i].to]=i;if (!vis[e[i].to]){vis[e[i].to]=1;q.push(e[i].to);}}vis[u]=0;}if (dis[t]==-inf/3) return 0;return 1;}void mcf(){int x=inf,i=t;while (pre[i]){x=min(x,e[pre[i]].c);i=e[pre[i]].from;}ansf+=x;ans+=dis[t]*x;i=t;while (pre[i]){e[pre[i]].c-=x;e[e[pre[i]].op].c+=x;i=e[pre[i]].from;}}int main(){//freopen("t2.in","r",stdin);//freopen("test.out","w",stdout);int T;scanf("%d",&T);while (T--){scanf("%d%d",&n,&m);for (int i=1;i<=n;i++)for (int j=1;j<=m;j++)scanf("%d",&hap[i][j]);memset(ls,0,sizeof(ls));for (int i=1;i<=n;i++){scanf("%d%d",&sum[i],&num[i]);if (sum[i]>=0&&num[i]>0){nx[i]=ls[num[i]];ls[num[i]]=i;}}for (int i=1;i<=m;i++)scanf("%d",&a[i]);s=0;t=n*2+m+1;cnt=0;for (int i=1;i<=n;i++)if (sum[i]>-1&&sum[i]>=a[num[i]]) sum[i]=-1;memset(last,0,sizeof(last));memset(v,0,sizeof(v));for (int i=1;i<=m;i++)fuck[i]=a[i];for (int i=1;i<=n;i++)insert(s,i,1,0);sum[1]=-1;for (int i=n;i>=1;i--)if (!v[num[i]]&&sum[i]<a[num[i]]&&sum[i]>-1){v[num[i]]=1;fuck[num[i]]=a[num[i]]-sum[i];}tot=n;for (int i=1;i<=m;i++){ls[i]=++tot;insert(tot,t,fuck[i],0);}for (int i=n;i>=1;i--){for (int j=1;j<=m;j++)insert(i,ls[j],1,hap[i][j]);if (sum[i]>-1){while (nx[i]&&(sum[nx[i]]>=sum[i]||sum[nx[i]]==-1)){sum[nx[i]]=-1;nx[i]=nx[nx[i]];}ls[num[i]]=++tot;if (nx[i]) insert(tot,t,sum[i]-sum[nx[i]],0);else insert(tot,t,sum[i],0);for (int j=i;j<=n;j++)insert(j,tot,1,hap[j][num[i]]);}}//for (int i=1;i<=cnt;i++)//if (i%2==1) printf("%d %d %d %d\n",e[i].from,e[i].to,e[i].c,e[i].w);ans=0;ansf=0;while (bfs()) mcf();if (ansf==n) printf("%d\n",ans);else printf("Warning!\n");}return 0;}


0 0
原创粉丝点击