本文将同步发布于:

  • 洛谷博客;
  • csdn;
  • 博客园;
  • 简书。

题目

题目链接:洛谷 AT4695、AtCoder agc031_e。

题意简述

在二维平面上,有 nnn 颗珠宝,第 iii 颗珠宝在 (xi,yi)(x_i,y_i)(xi​,yi​) 的位置,价值为 viv_ivi​。

现在有一个盗贼想要偷这些珠宝。

现在给出 mmm 个限制约束偷的珠宝,约束有以下四种:

  • 横坐标小于等于 aia_iai​ 的珠宝最多偷 bib_ibi​ 颗。
  • 横坐标大于等于 aia_iai​ 的珠宝最多偷 bib_ibi​ 颗。
  • 纵坐标小于等于 aia_iai​ 的珠宝最多偷 bib_ibi​ 颗。
  • 纵坐标大于等于 aia_iai​ 的珠宝最多偷 bib_ibi​ 颗。

现在问你在满足这些约束的条件下,盗贼偷的珠宝的最大价值和是多少。

题解

约束与转化

这个约束有点难办,似乎并没有可能对其进行动态规划,因此我们考虑额外添加信息。

我们添加什么信息呢?考虑到限制是有关珠宝数量的,我们决定添加一个 偷珠宝的总数 的信息。

设偷珠宝 kkk 颗,并且珠宝按照的横坐标排序被偷的顺序编号为 1∼k1\sim k1∼k,那么前两种限制条件转化如下:

  • 横坐标小于等于 aia_iai​ 的珠宝最多偷 bib_ibi​ 颗:
    若一个珠宝的编号 id∈[bi+1,k]\texttt{id}\in[b_i+1,k]id∈[bi​+1,k],那么一定有 xid>aix_{\texttt{id}}>a_ixid​>ai​。
  • 横坐标大于等于 aia_iai​ 的珠宝最多偷 bib_ibi​ 颗:
    若一个珠宝的编号 id∈[1,k−bi]\texttt{id}\in[1,k-b_i]id∈[1,k−bi​],那么一定有 xid<aix_{\texttt{id}}<a_ixid​<ai​。

同理,我们可以得出珠宝按照的纵坐标排序被偷的顺序编号为 1∼k1\sim k1∼k,那么后两种限制条件转化如下:

  • 纵坐标小于等于 aia_iai​ 的珠宝最多偷 bib_ibi​ 颗:
    若一个珠宝的编号 id∈[bi+1,k]\texttt{id}\in[b_i+1,k]id∈[bi​+1,k],那么一定有 yid>aiy_{\texttt{id}}>a_iyid​>ai​。
  • 纵坐标大于等于 aia_iai​ 的珠宝最多偷 bib_ibi​ 颗:
    若一个珠宝的编号 id∈[1,k−bi]\texttt{id}\in[1,k-b_i]id∈[1,k−bi​],那么一定有 yid<aiy_{\texttt{id}}<a_iyid​<ai​。

因此,我们得出,一个珠宝想要在按横坐标排序为第 iii,纵坐标排序为第 jjj 时被偷,需要满足的坐标范围。

化腐朽为神奇的网络流

考虑上面的条件也不是很好动态规划,我们需要想到一种化腐朽为神奇的算法——网络流。

由于这个题目有多个互不相关的限制:

  • 珠宝不能同时被偷两次及以上;
  • 偷的珠宝价值要最大化;

我们考虑运用费用流建立网络流模型。

因为我们要限制横坐标,所以必须要有 kkk 个横坐标的限制,对应 s→p1∼ks\to p_{1\sim k}s→p1∼k​,流量为 111,费用为 000。。

因为我们要限制纵坐标,所以必须要有 kkk 个纵坐标的限制,对应 q1∼k→tq_{1\sim k}\to tq1∼k​→t,流量为 111,费用为 000。

因为我们要限制一个点不能被选择多次,所以我们需要拆点限流,对应 a1∼n→b1∼na_{1\sim n}\to b_{1\sim n}a1∼n​→b1∼n​,流量为 111,费用为 viv_ivi​。

考虑到我们上面需要满足的限制,按照限制加边 pi→ajp_i\to a_jpi​→aj​ 和 bj→qib_j\to q_ibj​→qi​ 即可,流量为 111,费用为 000。

如果上面的语言有点抽象,我们不妨画图理解。

整个建图如上所示,点数为 Θ(n2)\Theta(n^2)Θ(n2),边数 Θ(n2)\Theta(n^2)Θ(n2)。

参考程序

#include<bits/stdc++.h>
using namespace std;
#define reg register
typedef long long ll;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
static char buf[1<<21],*p1=buf,*p2=buf;
inline int read(void){reg char ch=getchar();reg int res=0;while(!isdigit(ch))ch=getchar();while(isdigit(ch))res=10*res+(ch^'0'),ch=getchar();return res;
}inline ll readll(void){reg char ch=getchar();reg ll res=0;while(!isdigit(ch))ch=getchar();while(isdigit(ch))res=10*res+(ch^'0'),ch=getchar();return res;
}inline int max(reg int a,reg int b){return a>b?a:b;
}inline int min(reg int a,reg int b){return a<b?a:b;
}inline ll max(reg ll a,reg ll b){return a>b?a:b;
}const int MAXN=80+5;
const int MAXM=320+5;
const int inf=0x3f3f3f3f;namespace Network{const int MAXV=4*MAXN;const int MAXE=(MAXN*MAXN*2+3*MAXN)*2;const ll inf=0x3f3f3f3f3f3f3f3f;int cnt,head[MAXV],to[MAXE],w[MAXE],Next[MAXE];ll p[MAXE];inline void Add_Edge(reg int u,reg int v,reg int len,reg ll val){Next[++cnt]=head[u];to[cnt]=v,w[cnt]=len,p[cnt]=val;head[u]=cnt;return;}inline void Add_Tube(reg int u,reg int v,reg int len,reg ll val){Add_Edge(u,v,len,val);Add_Edge(v,u,0,-val);return;}bool inque[MAXV];int cur[MAXV];ll dis[MAXV];queue<int> Q;inline bool spfa(int s,reg int t){fill(dis+s,dis+t+1,inf);inque[s]=true,dis[s]=0,Q.push(s);while(!Q.empty()){reg int u=Q.front();Q.pop();inque[u]=false;cur[u]=head[u];for(reg int i=head[u];i;i=Next[i]){int v=to[i];if(dis[v]>dis[u]+p[i]&&w[i]){dis[v]=dis[u]+p[i];if(!inque[v]){inque[v]=true;Q.push(v);}}}}return dis[t]!=inf;}bool vis[MAXV];inline int dfs(reg int u,reg int t,reg ll lim){if(u==t)return lim;vis[u]=true;reg int flow=0;for(reg int &i=cur[u];i;i=Next[i]){reg int v=to[i];if(dis[v]==dis[u]+p[i]&&w[i]&&!vis[v]){reg int f=dfs(v,t,min(lim-flow,w[i]));if(f){flow+=f;w[i]-=f,w[i^1]+=f;if(flow==lim)break;}}}vis[u]=false;return flow;}inline pair<int,ll> dinic(reg int s,reg int t){int res=0;ll cost=0;while(spfa(s,t)){reg int flow=dfs(s,t,inf);res+=flow,cost+=flow*dis[t];}return make_pair(res,cost);}inline void init(reg int s,reg int t){cnt=1,fill(head+s,head+t+1,0);return;}
}struct Point{int x,y;ll v;
};struct Limits{char ch;int a,b;
};struct Interval{int l,r;inline Interval(reg int l=0,reg int r=0):l(l),r(r){return;}inline bool in(reg int x)const{return l<=x&&x<=r;}
};inline Interval cap(const Interval& a,const Interval& b){return Interval(max(a.l,b.l),min(a.r,b.r));
}int n,m;
Point a[MAXN];
Limits b[MAXM];int main(void){n=read();for(reg int i=1;i<=n;++i)a[i].x=read(),a[i].y=read(),a[i].v=readll();m=read();for(reg int i=1;i<=m;++i){dob[i].ch=getchar();while(!isalpha(b[i].ch));b[i].a=read(),b[i].b=read();}reg ll ans=0;for(reg int k=1;k<=n;++k){static Interval invx[MAXN],invy[MAXN];fill(invx+1,invx+k+1,Interval(-inf,inf));fill(invy+1,invy+k+1,Interval(-inf,inf));for(reg int i=1;i<=m;++i){switch(b[i].ch){case 'L':{for(reg int j=b[i].b+1;j<=k;++j)invx[j]=cap(invx[j],Interval(b[i].a+1,inf));break;}case 'R':{for(reg int j=1;j<=k-b[i].b;++j)invx[j]=cap(invx[j],Interval(-inf,b[i].a-1));break;}case 'D':{for(reg int j=b[i].b+1;j<=k;++j)invy[j]=cap(invy[j],Interval(b[i].a+1,inf));break;}case 'U':{for(reg int j=1;j<=k-b[i].b;++j)invy[j]=cap(invy[j],Interval(-inf,b[i].a-1));break;}}}reg int s=0,t=2*k+2*n+1;Network::init(s,t);for(reg int i=1;i<=k;++i){Network::Add_Tube(s,i,1,0);Network::Add_Tube(k+n+n+i,t,1,0);}for(reg int i=1;i<=n;++i)Network::Add_Tube(k+i,k+n+i,1,-a[i].v);for(reg int i=1;i<=k;++i)for(reg int j=1;j<=n;++j){if(invx[i].in(a[j].x))Network::Add_Tube(i,k+j,1,0);if(invy[i].in(a[j].y))Network::Add_Tube(k+n+j,k+n+n+i,1,0);}pair<int,ll> res=Network::dinic(s,t);if(res.first==k)ans=max(ans,-res.second);}printf("%lld\n",ans);return 0;
}

「题解」agc031_e Snuke the Phantom Thief相关推荐

  1. AtCoder AGC031E Snuke the Phantom Thief (费用流)

    题目链接 https://atcoder.jp/contests/agc031/tasks/agc031_e 题解 做法一(我的做法) 这是我yy出来的一个上下界费用流做法,自己没找到什么反例,能过. ...

  2. 「题解」蝙蝠侠的麻烦

    没 事 找 事 「我的做题历程」: step1:观察题面.   「蝙蝠侠需要找到一个最长的字符串,使得这个字符串作为一个子序列被包含在所有的三个字符串中」,可以得出这是一道最长公共子序列,而且有三个字 ...

  3. 「题解」:[组合数学]:Perm 排列计数

    题干: Description称一个1,2,-,N的排列P1,P2-,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,-N的排列中有多少是Magic的,答 ...

  4. 「题解」:[BZOJ4558]方

    问题: 方 时间限制: 2 Sec  内存限制: 256 MB 题面 题目描述 上帝说,不要圆,要方,于是便有了这道题.由于我们应该方,而且最好能够尽量方,所以上帝派我们来找正方形 上帝把我们派到了一 ...

  5. 「题解」300iq Contest 2 B Bitwise Xor

    本文将同步发布于: 洛谷博客: csdn: 博客园: 简书. 题目 题目链接:gym102331B. 题意概述 给你一个长度为 nnn 的序列 aia_iai​,求一个最长的子序列满足所有子序列中的元 ...

  6. 「题解」:[线段树]:永无乡

    题面 题目描述 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 ...

  7. 「题解」USACO15FEB Fencing the Herd G

    本文将同步发布于: 洛谷博客: csdn: 博客园: 简书: 题目 题目链接:洛谷 P3122.USACO 官网. 题意概述 给你平面上的一些点和直线,有两种操作: 新加入一个点 (x,y)(x,y) ...

  8. 「题解」300iq Contest 2 H. Honorable Mention

    本文将同步发布于: 洛谷博客: csdn: 博客园: 简书. 题目 题目链接:gym102331H. 题意概述 给定一个长度为 n n n 的序列 a a a,有 q q q 次询问,每次询问给定三个 ...

  9. 「题解」老鼠与猫的交易

    题目描述 有一只老鼠很喜欢奶酪,但是奶酪被分别放在N个房间里,而且这些房间都有一只猫咪看守,现在它准和猫咪们 做个交易.它有M磅的猫食,想用这M磅猫食换取奶酪.在猫咪看守的每一个房间里有奶酪J[i]磅 ...

  10. 「题解」清华集训 2016 你的生命已如风中残烛

    本文将同步发布于: 洛谷博客: csdn: 博客园: 简书: 题目 题目链接:洛谷 P6672.UOJ 273. 题意简述 给你牌数为 m + 1 m+1 m+1 的牌堆,其中第 m + 1 m+1 ...

最新文章

  1. 人工智能医疗是把双刃剑,“对抗性攻击”后可导致误判
  2. D-query SPOJ - DQUERY (莫队算法裸题)
  3. STM32F105 PA9/OTG_FS_VBUS Issues
  4. Linux模块加载流程及如何让系统开机自动加载模块
  5. Spring框架是如何判断是否是上传文件请求呢
  6. 关于多线程的几个问题
  7. 5G 即将带来冲击!| 畅言
  8. ftp服务器连接不了文件路径,Serv-U和CuteFTP无法连接FTP服务器问题解答
  9. 小宝图盟机器人软件开发平台
  10. 零信任安全架构03-适用场景及实施建议
  11. 在群辉(NAS)中安装虚拟机套件(Virtual Machine Manager)
  12. 讯飞aiui的webapi+python使用记录
  13. python-图片颜色转换-将红绿两色互换
  14. jquery触发键盘按下事件
  15. 在线ps html源码,PSD to HTML5 - 专业前端切图(PSDoHTML.com)
  16. 阿根廷绝杀尼日尼亚给我们互联网建站者带来什么启示?
  17. P2495 [SDOI2011]消耗战
  18. 电脑找不到WLAN找不到WiFi功能块
  19. 一道面试题引出的系列数据库性能,数据安全问题及解决方案
  20. PYTHON---下三角矩阵的判断

热门文章

  1. 谷歌又放大招 Disco Diffusion!AI生成超高质量绘画!
  2. Vue3中使用生命周期函数
  3. 一个img文件-实验吧
  4. DUBBO服务为null的情况
  5. SHU 购买装备 贪心+二分
  6. Linux提高CPU使用率并设置固定占比
  7. selenium tbody表单获取封装函数
  8. wireshark抓web包
  9. matlab 买什么电脑配置,要快速运行Matlab,电脑用什么配置和系统好
  10. SQLite 生成随机数字、字符串、日期、验证码以及 UUID