#575. 【ULR #1】光伏元件

好牛的题

首先行、列拆点,\(i\)表示第\(i\)行,\(i+n\)表示第\(i\)列

先考虑如何表达\(|c_{0,i}-c_{1,i}|\leq k\)这一限制,我们假设\(t=\min(c_{0,i},c_{1,i})\),则\(c_{0,i}\leq t+k\)且\(c_{1,i}\leq t+k\),那么考虑建一条边,\((i+n,i,t,0)\),这样的话,就用\(i\)的入流表示第\(i\)行的\(1\)的个数,\(i+n\)的出流表示第\(i+n\)行的\(1\)的个数,对于拆成的两个限制,连边\((s,i,[0,k],0)\),\((i+n,t,[0,k],0)\)即可,不难发现\(t\in[l,r-k-l]\)时能恰好表示所有的情况,但此时\(t\)的含义已经不仅是\(min\)值了,这里\(k\)对\(r-l\)取\(min\)

对于\(a_{i,j}=1\),先建边\((i,j+n,[1,1],0)\),这里相当于强制让\(i\)和\(j+n\)都会分别至少有一个入流和一个出流(为什么要这么别扭的建边呢,因为我们前文提到用\(i\)的入流表示第\(i\)行\(1\)的数量,\(i+n\)的出流表示第\(i+n\)行的\(1\)的个数,那么既然我们的第一个限制条件是用\((s,i)\),\((i+n,t)\),\((i+n,i)\)这些边表示出来的,那么我们后面就不能破坏这些限制条件,具体来说,就是\(i\)不能添加新的入边,\(i+n\)不能添加新的出边),然后若这个点能修改,那么其实就相当于反悔操作,建边\((j+n,i,[0,1],c_{i,j})\)即可(因为这里相当于是反悔,也就是说,这条边是基于满足第一个限制之上的,选择这条边只是相当于去除\(i\)和\(j+n\)分别一条合法的入边和出边,去除过后的肯定也是合法的,所以此处\(i\)的入边、\(j+n\)的出边是合法的)

对于\(a_{j,i}=0\),建边\((i,j+n,[0,1],c_{i,j})\)

然后这就是一个有源汇上下界费用流了,保证有解,直接跑就行

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=105,INF=1e9;
const ll inf=1e18;
int n,a[N][N],d[N<<1],s,t,S,T,edge[N][N];
ll ans;
int head[N<<1],cnt=1;
struct node{
int nxt,v,val,w;
}tree[N*(N+5)<<1];
void add(int u,int v,int val,int w=0){
tree[++cnt]={head[u],v,val,w},head[u]=cnt;
tree[++cnt]={head[v],u,0,-w},head[v]=cnt;
}
ll dis[N<<1];
bool vis[N<<1];
queue<int> q;
bool SPFA(){
for(int i=1;i<=T;++i) dis[i]=inf,vis[i]=false;
dis[S]=0,q.push(S);
while(!q.empty()){
int x=q.front(); q.pop(),vis[x]=false;
for(int i=head[x],y;i;i=tree[i].nxt) if(tree[i].val&&dis[y=tree[i].v]>dis[x]+tree[i].w){
dis[y]=dis[x]+tree[i].w;
if(!vis[y]) vis[y]=true,q.push(y);
}
}
return dis[T]<inf;
}
int dinic(int x,int flow){
if(x==T) return flow;
int r=flow; vis[x]=true;
for(int i=head[x],y;i;i=tree[i].nxt) if(dis[y=tree[i].v]==dis[x]+tree[i].w&&tree[i].val&&!vis[y]){
int k=dinic(y,min(r,tree[i].val));
if(!k) dis[y]=INF;
tree[i].val-=k,tree[i^1].val+=k,r-=k,ans+=1ll*k*tree[i].w;
if(!r) return flow;
}
vis[x]=false;
return flow-r;
}
int main(){
scanf("%d",&n),s=(n<<1)+1,t=s+1,S=t+1,T=S+1;
for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) scanf("%d",&a[i][j]),(a[i][j])&&(--d[i],++d[j+n]);
for(int i=1,v;i<=n;++i) for(int j=1;j<=n;++j)
if(scanf("%d",&v),v>=0){
if(a[i][j]) add(j+n,i,1,v); else add(i,j+n,1,v);
edge[i][j]=cnt;
}
add(t,s,INF);
for(int i=1,l,r,k;i<=n;++i){
scanf("%d%d%d",&l,&r,&k),k=min(k,r-l);
d[i]+=l,d[i+n]-=l,add(s,i,k),add(i+n,t,k),add(i+n,i,r-k-l);
}
for(int i=1;i<=t;++i){
if(d[i]<0) add(i,T,-d[i]);
if(d[i]>0) add(S,i,d[i]);
}
while(SPFA()) dinic(S,INF);
printf("%lld\n",ans);
for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) printf("%d%c",a[i][j]^tree[edge[i][j]].val,(j==n)?'\n':' '); return 0;
}

核心就是这里对于限制关系的表达,将\(|a-b|\leq c\)变成了\(d=\min(a,b)\),\(b\leq d+c\)且\(a\leq d+c\),其它的都是基于这一步推出

另一个比较重要的就是,当我们基于某一种对于一类边的定义、建出了满足某一限制的边之后,再去做其他的限制时,不能再使用这一类边,因为会破坏这一限制,但是有一种例外,就是我们建出了这一类边的一个反边\(a\),然后再建出\(a\)的反边\(b\)(\(b\)肯定是属于这一类边的),此时若满足只有\(a\)被选中了之后,才能选中\(b\),那么这个\(b\)也是允许存在的,也就是说,\(b\)是\(a\)的反悔,此时因为选中\(a\)的时候是一定合法的,所以\(b\)将其反悔掉了过后整个局面也是合法的

UOJ 575 光伏元件的更多相关文章

  1. ULR1 B. 【ULR #1】光伏元件

    一个n∗nn∗n的0101矩阵ai,jai,j,有些位置可以修改,代价为ci,jci,j.要求进行一些修改之后满足:设clicli为第ii行的11的个数,cricri为第ii列的11的个数,要求cli ...

  2. 04讲 正确使用heterogeneous类型的元件

    heterogeneous类型的元件1.可能出现的错误     再使用数个heterogeneous 元件的时候会因为分部件的不匹配 2.出现错误的原因原因是这四个运放,软件它并不识别那两个是配在一起 ...

  3. 虚拟机上装uoj

    前期准备: x64 ubuntu 镜像.vmware.ss账号 注意一定要有64位镜像! ss不是必须的,不过没有的话就等着下载一晚上吧... 首先先装好ubuntu,我装的是ubuntu-16.04 ...

  4. 【UOJ #35】后缀排序 后缀数组模板

    http://uoj.ac/problem/35 以前做后缀数组的题直接粘模板...现在重新写一下模板 注意用来基数排序的数组一定要开到N. #include<cstdio> #inclu ...

  5. 建模元件有哪些在MapleSim中

    信号库:包含通用信号模块.布尔.控制器.离散信号模块.信号源.线性信号模块.非线性信号模块.时间离散信号模块.查询表.信号转换器.数学运算.关系元件.特殊信号模块,应用案例. 电子库:包含电阻.运算放 ...

  6. JMeter专题系列(三)元件的作用域与执行顺序

    1.元件的作用域 JMeter中共有8类可被执行的元件(测试计划与线程组不属于元件),这些元件中,取样器是典型的不与其它元件发生交互作用的元件,逻辑控制器只对其子节点的取样器有效,而其它元件(conf ...

  7. jmeter(六)元件的作用域与执行顺序

    jmeter是一个开源的性能测试工具,它可以通过鼠标拖拽来随意改变元件之间的顺序以及元件的父子关系,那么随着它们的顺序和所在的域不同,它们在执行的时候,也会有很多不同. jmeter的test pla ...

  8. 分布式光伏系列:分布式光伏电站 运行与维护方案一览(zz)

    原文:http://www.toutiao.com/a6353487210709516546/ 中小型光伏电站的特点是占地面积小.安装位置灵活且日常维护量少.由于光伏电站不同的运行环境,为了能够使光伏 ...

  9. 【UOJ #246】【UER #7】套路

    http://uoj.ac/contest/35/problem/246 神奇!我这辈子是想不出这样的算法了. 对区间长度分类讨论:题解很好的~ 我已经弱到爆了,看完题解后还想了一晚上. 题解中&qu ...

  10. 【UOJ #244】【UER #7】短路

    http://uoj.ac/contest/35/problem/244 对其他人来说好简单的一道题,我当时却不会做TWT 注定滚粗啊 题解很好的~ #include<cstdio> #i ...

随机推荐

  1. 初始化参数之memory_target

    一.引言: Oracle 9i引入pga_aggregate_target,可以自动对PGA进行调整: Oracle 10g引入sga_target,可以自动对SGA进行调整: Oracle 11g则 ...

  2. C# - 获取枚举描述 - 使用增量源生成器

    前言 C# 获取枚举描述的方法有很多, 常用的有通过 DescriptionAttribute 反射获取, 进阶的可以加上缓存机制, 减少反射的开销.今天我们还提供一种更加高效的方法,通过增量源生成器 ...

  3. Shell语言编程(炼气)

    1. Shell脚本执行方式 执行方式 应用及场景 通过sh或bash 书写脚本后,最常用的方式,在其他非红帽系统中,建议使用bash运行脚本 通过.点或source 加载/生效配置文件(环境变量,别 ...

  4. MySQL-删除数据和count(*)原理

    delete删除数据原理 在InndoDB存储引擎中,delete删除操作是把需要删除的数据或者页标记为已删除,后面如果有需要,直接复用即可.这些被标记为已经删除的数据,看起来就像空洞一样.所以看起来 ...

  5. ArrayList的常用成员方法

    1.ArrayList常用成员方法 可以大致分为4种,增 删 改 查 1.增 1.public boolean add(E e) 将括号里的元素直接添加到集合中,添加的元素按照顺序依次排列. 其中,E ...

  6. Visual Studio 中的 .sln 和 .suo 文件

    解决方案文件1 Visual Studio 采用两种文件类型 .sln & .suo 来存储特定于解决方案的设置.这些文件总称为解决方案文件,为解决方案资源管理器提供显示管理文件的图形接口所需 ...

  7. Cursor预测程序员行业倒计时:CTO应做好50%裁员计划

    提供AI咨询+AI项目陪跑服务,有需要回复1 前两天跟几个业内同学做了一次比较深入的探讨,时间从15.00到21.00,足足6个小时! 其中有个问题特别有意思:从ChatGPT诞生到DeepSeek爆 ...

  8. iOS Facebook和Google登录

    前言 最近在对接完Google和Facebook登录之后准备对这部分内容做一个小小的总结,方便以后有需要的时候查看. 具体的Google账号申请和Facebook账号的申请在这里就不做介绍了,这部分内 ...

  9. Postman接口关联总结

    1.新建集合 打开postman,点击Collections->New Collection,页面如下: 2.新建请求 下面以获取绑定信息接口为例 接口说明: C{获取绑定信息接口} 接口地址: ...

  10. Redis的底层数据结构-跳表

    跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其它节点的指针,从而达到快速访问节点的目的.具有如下性质: 1.由很多层结构组成: 2.每一层都是一个有序的链表,排列顺序为 ...