#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. 探秘Transformer系列之(17)--- RoPE

    探秘Transformer系列之(17)--- RoPE 目录 探秘Transformer系列之(17)--- RoPE 文章总表 0x00 概述 0x01 总体思路 1.1 注意力机制回顾 1.2 ...

  2. MaxKB+Ollama 离线部署

    主题:在 Centos7 环境部署 MaxKB 以及 Ollama 实现基于离线大模型的的小助手调用. 选择离线部署的原因:原计划是打算直接使用 1Panel 进行 MaxKB 和 Ollama 一键 ...

  3. 2024 蓝桥杯模拟赛3(div1+div2)

    2024 蓝桥杯模拟赛3(div1+div2) P8834 [传智杯 #3 决赛] 序列 简单的模拟,数据范围很小,暴力即可 点击查看代码 #include <bits/stdc++.h> ...

  4. Docker安装elasticsearch、kibana、ik分词器

    一.下载ealastic search和kibana,两者的版本要一致 docker pull elasticsearch:7.6.2 docker pull kibana:7.6.2 二.配置 mk ...

  5. Hystrix两种隔离方式对比

    ​在微服务架构中,我们不可避免的与Hystrix打交道,最近在面试过程中,也总是被问到Hystrix两种熔断方式的区别,今天,就给大家做个小结. 首先,Hystrix熔断方式主要有两种: 线程池隔离 ...

  6. 一文速通 Python 并行计算:07 Python 多线程编程-线程池的使用和多线程的性能评估

    一文速通 Python 并行计算:07 Python 多线程编程-线程池的使用和多线程的性能评估 摘要: 本文介绍了 Python 线程池(ThreadPoolExecutor)的使用方法,包括线程池 ...

  7. 1.3K star!VisActor团队开源神器,3秒生成商业级图表,程序员直呼真香!

    嗨,大家好,我是小华同学,关注我们获得"最新.最全.最优质"开源项目和高效工作学习方法 项目速览 VChart 是VisActor团队推出的高性能可视化解决方案,GitHub斩获2 ...

  8. 自定义工具类之”判断两个集合中是否有一个相同的值-》CollectionUtils.containsAny(集合1,集合2)“

    判断两个集合中是否有一个相同的值 CollectionUtils.containsAny(集合1,集合2)就可以满足以下条件 两个集合中,只要有一个值相同就直接返回true 如:集合1:"1 ...

  9. 工具:河马 WebShell扫描器 for Linux 使用教程

    安装教程: 1.下载 访问https://www.shellpub.com官方网站 2.选择适合您的版本 cat /proc/version linux 64位选择 linux amd64linux ...

  10. RPC实战与核心原理之时钟轮

    时钟轮在RPC中的应用 回顾 在分布式环境下,RPC 框架自身以及服务提供方的业务逻辑实现,都应该对异常进行合理地封装,让使用方可以根据异常快速地定位问题:而在依赖关系复杂且涉及多个部门合作的分布式系 ...