P8215-[THUPC2022 初赛]分组作业【网络流】

1|0正题

题目链接:https://www.luogu.com.cn/problem/P8215


1|1题目大意

2×n个人,第2×i1和第2×i个人一组,然后每个人可以选择愿不愿意合作,愿意需要付出ci代价,不愿意是di代价,如果两个人都愿意,可以选择合作。如果一个人选择愿意另一个人不愿意,那么愿意的那个人会产生ei的代价。

然后给出m对关系,然后题目描述开摆了
在这里插入图片描述
1n5000,0m10000,1ai,bi,ci,di,ei109


1|2解题思路

首先考虑c,d,e的贡献,考虑用最小割。

首先c,d要选一个,所以它们肯定是串在一个点上的,所以SiTSi的流量为ciT的流量为d
然后e的贡献就是一个选c一个选d时的贡献,所以我们可以让i连向它的队友,流量为e,如果i选了c,它队友选了d,那么这条e的边也要割。
然后因为还有一个选择是否合作,但是要求所有的都选择c的贡献,所以我们让新建一个点WSW的一条边表示是否合作(如果连了就表示合作),然后W连向同一个队的两个点,

那么一个小组的图大概就长这样
在这里插入图片描述

然后考虑后面的贡献就很麻烦了
在这里插入图片描述
这一个我们可以直接让B所在组的W点连接A点就行了,如果A选了dB的合作边没被割掉,那么刚好这条路就是通的,也需要被割掉。

至于
在这里插入图片描述
这个贡献,我们考虑反过来处理。
我们发现SWi这条边还没有权值,我们可以先默认如果A没有合作就会产生ai的代价,然后如果B选择了不愿意,那么就会少产生ai的贡献,我们让Bd值减去ai
然后发现如果此时A没有合但是B不愿意也会少产生这个贡献,我们让WA连向B费用为ai,这样这种情况就不会少算了。
然后因为d可能减到负数,我们可以让所有的cd加上一个大整数,然后最后统一减去这部分贡献就好了。

这样就完美处理完了所有的条件


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define ll long long using namespace std; const ll N=5100*6; struct node{ ll to,next,w; }a[N<<4]; ll n,m,s,t,c[N],d[N],e[N],w[N]; ll tot=1,ls[N],dep[N],ans; queue<ll> q; void addl(ll x,ll y,ll w){ a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w; a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0; return; } bool bfs(){ while(!q.empty())q.pop(); memset(dep,0,sizeof(dep)); dep[s]=1;q.push(s); while(!q.empty()){ ll x=q.front();q.pop(); for(ll i=ls[x];i;i=a[i].next){ ll y=a[i].to; if(!a[i].w||dep[y])continue; dep[y]=dep[x]+1; if(y==t)return 1; q.push(y); } } return 0; } ll dinic(ll x,ll flow){ ll rest=0,k; if(x==t)return flow; for(ll i=ls[x];i;i=a[i].next){ ll y=a[i].to; if(!a[i].w||dep[y]!=dep[x]+1)continue; rest+=(k=dinic(y,min(flow-rest,a[i].w))); a[i].w-=k;a[i^1].w+=k; if(rest==flow)return flow; } if(!rest)dep[x]=0; return rest; } signed main() { scanf("%lld%lld",&n,&m);s=3*n+1;t=s+1; for(ll i=1;i<=2*n;i++) scanf("%lld%lld%lld",&c[i],&d[i],&e[i]); for(ll i=1,x,y,a,b;i<=m;i++){ scanf("%lld%lld%lld%lld",&x,&y,&a,&b); ll A=(x+1)/2,B=(y+1)/2; addl(2*n+B,x,b); w[A]+=a;d[y]-=a; addl(2*n+A,y,a); } for(ll i=1;i<=2*n;i++){ addl(s,i,d[i]+1e14); addl(i,t,c[i]+1e14); ll p=(i&1)?(i+1):(i-1); addl(i,p,e[i]); } for(ll i=1;i<=n;i++){ addl(s,2*n+i,w[i]); addl(2*n+i,2*i-1,1e18); addl(2*n+i,2*i,1e18); } while(bfs()) ans+=dinic(s,1e18); printf("%lld\n",ans-200000000000000ll*n); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/16018719.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(79)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2021-03-17 P4643-[国家集训队]阿狸和桃子的游戏【结论】
2021-03-17 P6076-[JSOI2015]染色问题【组合数学,容斥】
点击右上角即可分享
微信分享提示