[hdu6978]New Equipments II
显然可以费用流来做,具体建图如下——
点集:源点,汇点,左边$n$个工人,右边$n$个设备
边集:源点向第$i$个工人连$(1,a_{i})$的边,第$i$个设备向汇点连$(1,b_{i})$的边,工人向可用的设备连$(1,0)$的边
跑最小费用最大流,流量为$i$时的费用即为$i$时的答案
但注意到要跑$n$次spfa,每一次的最坏复杂度为$o(n^{3})$,显然无法通过
实际上,spfa即找到$x$和$y$,使得第$x$个工人和第$y$个设备都未被使用过,且第$x$个工人能流到第$y$个设备,在此基础上最大化$a_{x}+b_{y}$,那么不妨手动来实现此功能
考虑按照$a_{i}$从大到小枚举左边未被使用过的的工人,并递归其能流到的点,求出其中设备$b_{i}$的最大值
注意到当一个点已经被访问过,显然再访问一定不优于之前,单次复杂度即降为$o(n^{2})$
每一个点只会被访问一次,因此复杂度瓶颈在于遍历边集,使用bfs来代替dfs,并对点分类讨论:
1.对于工人,其几乎到所有设备都有边,缺的仅有$o(m)$条限制和$o(n)$条之前流过的边,因此只需要遍历所有当前未被访问的点,并搜索其中可以访问的点
注意到一个未访问的点被遍历,要么被访问,要么属于$o(n+m)$条边之一,因此总复杂度即$o(m)$
2.对于设备,其出边只有$o(n)$条之前流过的边的反向边,暴力遍历边集即可,总复杂度即$o(n)$
由此,单次复杂度降为$o(m)$,总复杂度即$o(nm)$,可以通过


- 1 #include<bits/stdc++.h>
- 2 using namespace std;
- 3 #define N 4005
- 4 #define ll long long
- 5 queue<int>q;
- 6 vector<int>v[N];
- 7 int t,n,m,x,y,a[N],b[N],id[N],visa[N],visb[N],vis[N],nex[N],pre[N<<1],mx[N],e[N][N];
- 8 ll ans;
- 9 bool cmp(int x,int y){
- 10 return a[x]>a[y];
- 11 }
- 12 int bfs(int k){
- 13 int s=0;
- 14 q.push(k);
- 15 vis[k]=1;
- 16 while (!q.empty()){
- 17 int k=q.front();
- 18 q.pop();
- 19 if (k<=n){
- 20 for(int i=nex[0],j=0;i<=n;j=i,i=nex[i])
- 21 if (e[k][i]){
- 22 pre[i+n]=k;
- 23 q.push(i+n);
- 24 nex[j]=nex[i],i=j;
- 25 }
- 26 }
- 27 else{
- 28 k-=n;
- 29 if ((!visb[k])&&(b[s]<b[k]))s=k;
- 30 for(int i=0;i<v[k].size();i++)
- 31 if (!vis[v[k][i]]){
- 32 pre[v[k][i]]=k+n;
- 33 q.push(v[k][i]);
- 34 vis[v[k][i]]=1;
- 35 }
- 36 }
- 37 }
- 38 return s;
- 39 }
- 40 int calc(){
- 41 int ans=0;
- 42 for(int i=1;i<=n;i++)vis[i]=0;
- 43 for(int i=0;i<=n;i++)nex[i]=i+1;
- 44 for(int i=1;i<=(n<<1);i++)pre[i]=0;
- 45 for(int i=1;i<=n;i++){
- 46 mx[i]=0;
- 47 if ((!visa[id[i]])&&(!vis[id[i]])){
- 48 mx[i]=bfs(id[i]);
- 49 if (mx[i])ans=max(ans,a[id[i]]+b[mx[i]]);
- 50 }
- 51 }
- 52 if (!ans)return 0;
- 53 for(int i=1;i<=n;i++)
- 54 if ((mx[i])&&(a[id[i]]+b[mx[i]]==ans)){
- 55 visa[id[i]]=1,visb[mx[i]]=1;
- 56 for(int lst=mx[i]+n,j=pre[lst];j;lst=j,j=pre[j]){
- 57 if (j<=n){
- 58 e[j][lst-n]=0;
- 59 v[lst-n].push_back(j);
- 60 }
- 61 else{
- 62 e[lst][j-n]=1;
- 63 for(int k=0;k<v[j-n].size();k++)
- 64 if (v[j-n][k]==lst){
- 65 v[j-n].erase(v[j-n].begin()+k);
- 66 break;
- 67 }
- 68 }
- 69 }
- 70 break;
- 71 }
- 72 return ans;
- 73 }
- 74 int main(){
- 75 scanf("%d",&t);
- 76 while (t--){
- 77 scanf("%d%d",&n,&m);
- 78 ans=0;
- 79 for(int i=1;i<=n;i++){
- 80 visa[i]=visb[i]=0;
- 81 v[i].clear();
- 82 }
- 83 for(int i=1;i<=n;i++)
- 84 for(int j=1;j<=n;j++)e[i][j]=1;
- 85 for(int i=1;i<=n;i++){
- 86 scanf("%d",&a[i]);
- 87 id[i]=i;
- 88 }
- 89 sort(id+1,id+n+1,cmp);
- 90 for(int i=1;i<=n;i++)scanf("%d",&b[i]);
- 91 for(int i=1;i<=m;i++){
- 92 scanf("%d%d",&x,&y);
- 93 e[x][y]=0;
- 94 }
- 95 for(int i=1;i<=n;i++){
- 96 int s=calc();
- 97 if (!s){
- 98 for(;i<=n;i++)printf("-1\n");
- 99 break;
- 100 }
- 101 ans+=s;
- 102 printf("%lld\n",ans);
- 103 }
- 104 }
- 105 return 0;
- 106 }
[hdu6978]New Equipments II的更多相关文章
- Leetcode 笔记 113 - Path Sum II
题目链接:Path Sum II | LeetCode OJ Given a binary tree and a sum, find all root-to-leaf paths where each ...
- Leetcode 笔记 117 - Populating Next Right Pointers in Each Node II
题目链接:Populating Next Right Pointers in Each Node II | LeetCode OJ Follow up for problem "Popula ...
- 函数式Android编程(II):Kotlin语言的集合操作
原文标题:Functional Android (II): Collection operations in Kotlin 原文链接:http://antonioleiva.com/collectio ...
- 统计分析中Type I Error与Type II Error的区别
统计分析中Type I Error与Type II Error的区别 在统计分析中,经常提到Type I Error和Type II Error.他们的基本概念是什么?有什么区别? 下面的表格显示 b ...
- hdu1032 Train Problem II (卡特兰数)
题意: 给你一个数n,表示有n辆火车,编号从1到n,入站,问你有多少种出站的可能. (题于文末) 知识点: ps:百度百科的卡特兰数讲的不错,注意看其参考的博客. 卡特兰数(Catalan):前 ...
- [LeetCode] Guess Number Higher or Lower II 猜数字大小之二
We are playing the Guess Game. The game is as follows: I pick a number from 1 to n. You have to gues ...
- [LeetCode] Number of Islands II 岛屿的数量之二
A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand oper ...
- [LeetCode] Palindrome Permutation II 回文全排列之二
Given a string s, return all the palindromic permutations (without duplicates) of it. Return an empt ...
- [LeetCode] Permutations II 全排列之二
Given a collection of numbers that might contain duplicates, return all possible unique permutations ...
随机推荐
- python中return的返回和执行
1 打印函数名和打印函数的执行过程的区别 例子1.1 def a(): print(111) print(a) # 打印a函数的内存地址,不会对a函数有影响,a函数不会执行 print(a()) # ...
- 2021.5.22 vj补题
A - Marks CodeForces - 152A 题意:给出一个学生人数n,每个学生的m个学科成绩(成绩从1到9)没有空格排列给出.在每科中都有成绩最好的人或者并列,求出最好成绩的人数 思路:求 ...
- c++-string类--insert函数
string &insert(int p0, const char *s);--在p0位置插入字符串s string &insert(int p0, const char *s, in ...
- 后缀自动机(SAM)奶妈式教程
后缀自动机(SAM) 为了方便,我们做出如下约定: "后缀自动机" (Suffix Automaton) 在后文中简称为 SAM . 记 \(|S|\) 为字符串 \(S\) 的长 ...
- Java(8)详解Random使用
作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201556.html 博客主页:https://www.cnblogs.com/testero ...
- CAD网页Web端显示开发为什么要以WebGIS的思路来开发?
背景 在之前的博文CAD图DWG解析WebGIS可视化技术分析总结中讲解了如何把CAD的DWG格式的图纸Web可视化的方案.博文发布后,受到不少同行们的关注,也有不少咨询一些专业问题,其中大家可能疑惑 ...
- Google Style Guides
Google Style Guides Google Style Guides Google 开源项目风格指南 (zh-google-styleguide.readthedocs.io)
- python解释器和Pycharm编辑器安装使用完整详细教程
一.官网下载或软件管家公众号下载 二.安装Python解释器 1.选择自定义安装并添加到环境变量 2.检验Python是否安装成功 三.安装pycharm编辑器 1.点击安装,修改安装路径,建议安装C ...
- airtest常用指令
airtest 操作adb命令 常用adb 1)对特定设备执行adb指令 dev = connect_device("Android:///device1") dev.shel ...
- elasticsearch的索引重建
我们知道es在字段的mapping建立后就不可再次修改mapping的值.在我们实际的情况下有些时候就是需要修改mapping的值,解决方案就是重新构建索引数据. 方式一 : 使用索引别名,创建另外一 ...