jzoj 4718. 【GDOI2017模拟7.20】准备食物2 费用流
来源:互联网 发布:windows中的用户账户 编辑:程序博客网 时间:2024/05/17 01:22
分析:如果没有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
- jzoj 4718. 【GDOI2017模拟7.20】准备食物2 费用流
- 【GDOI2017模拟8.20】准备食物2
- 【JZOJ 4598】准备食物
- 【JZOJ 4598】 准备食物
- jzoj 4690. 【GDOI2017模拟8.12】躲藏 网络流
- JZOJ 4863. 【GDOI2017模拟11.5】Market
- JZOJ 4863 【GDOI2017模拟11.5】Market
- jzoj【GDOI2017第二轮模拟day2】开房间
- JZOJ4718. 准备食物2
- [jzoj4598]【NOIP2016模拟7.9】准备食物
- jzoj 4690. 【GDOI2017模拟8.12】字符串 后缀数组+RMQ
- jzoj 4702. 【GDOI2017模拟8.15】Game 状压dp+减枝
- jzoj 4684. 【GDOI2017模拟8.11】卡牌游戏 线段树
- jzoj 4683. 【GDOI2017模拟8.11】矩阵 后缀数组+哈希表
- JZOJ 4739 【雅礼联考GDOI2017模拟9.2】Ztxz16学图论
- jzoj 4848. 【GDOI2017模拟11.3】永恒的契约 单调栈
- JZOJ 4915. 【GDOI2017模拟12.9】最长不下降子序列
- JZOJ 5050. 【GDOI2017模拟一试4.11】颜色树
- codeforces 374D 树状数组或者线段树
- Windows线程创建、退出及资源释放
- 【机器学习实战04】k-均值聚类算法
- 进程同步之信号量机制(pv操作)及三个经典同步问题
- 让你的程序性能获得百倍的提升—Redis基础使用指南
- jzoj 4718. 【GDOI2017模拟7.20】准备食物2 费用流
- javaweb中的filter
- UVA 7392 Bundles of Joy(乱搞)
- Redis和Memcache的区别
- Http--基础理解
- java中懒汉饿汉编写及比较
- 腾讯web前端2016面试
- 翻转子串的解题技巧
- #248 Count of Smaller Number