codeforces103E Buying Sets
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!
题目链接:codeforces103E
正解:网络流+最小权闭合图
解题报告:
考虑这道题的模型。
首先因为存在完备匹配,所以可以给每个点找一个匹配点,然后这个点向所需要的药材的匹配点连边。
然后我们可以得到一个选择一个点就要选择它的所有出边的最小闭合权子图的模型,取个负号跑最大权闭合子图就好了,直接套板子。
这样建图的正确性可以意会一下,很明显可以起到选一个就选另一个的效果。
补一发最大权闭合子图的理解:
很久以前学过但是忘得差不多了。
这类题的模型就是一个每个点带权的有向图,选择了一个点就要选择他的所有出边,最大化选出的点的最大权值和。
建图的方法就是$S$向正权点连容量为点权的边,原图的边容量为$inf$,负权点向$T$连容量为点权的绝对值的边。
先默认选择所有的正权点,$ans$的初值就是正权点的点权之和,而实际情况下可能有些正权点不选,还要另选择一些负权点。
那么$ans=ans-$(不选择正权$+$选择的负权的绝对值),后者就是图的最小割,也就是最大流。
考虑最小割只能与$S$或$T$相连。
与$S$相连的点说明供应$<=$出边流量,那么显然是不选择的正权,因为选了不划算;
与$T$相连的说明,为其提供流量的边还未满,那么这个负权就是选择了正权之后付出的一些负权点代价,显然会划算。
//It is made by ljh2000
//有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <cmath>
#include <ctime>
using namespace std;
typedef long long LL;
const int MAXN = 15001;
const int inf = (1<<29);
int n,P[MAXN],Tim,match[MAXN],vis[MAXN];
vector<int>medi[MAXN];
LL ans; inline int getint(){
int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
} namespace network{
const int MAXM = 1000011;
int ecnt,first[MAXN],S,T,dui[MAXN],deep[MAXN];
queue<int>q;
struct edge{ int to,f,next; }e[MAXM];
inline void Init(){ ecnt=1; S=n+1; T=S+1; }
inline void link(int x,int y,int z){
e[++ecnt].next=first[x]; first[x]=ecnt; e[ecnt].to=y; e[ecnt].f=z;
e[++ecnt].next=first[y]; first[y]=ecnt; e[ecnt].to=x; e[ecnt].f=0;
} inline bool bfs(){
for(int i=1;i<=T;i++) deep[i]=-1; deep[S]=0; q.push(S); int u;
while(!q.empty()){
u=q.front(); q.pop();
for(int i=first[u];i;i=e[i].next) {
if(e[i].f==0) continue;
int v=e[i].to; if(deep[v]!=-1) continue;
deep[v]=deep[u]+1; q.push(v);
}
}
return (deep[T]!=-1);
} inline int dinic(int x,int remain){
if(x==T || remain==0) return remain;
int f,flow=0;
for(int i=first[x];i;i=e[i].next) {
if(e[i].f==0) continue;
int v=e[i].to; if(deep[v]!=deep[x]+1) continue;
f=dinic(v,min(remain,e[i].f));
if(f==0) deep[v]=-1;
else {
flow+=f; remain-=f;
e[i].f-=f; e[i^1].f+=f;
if(remain==0) return flow;
}
}
return flow;
}
} inline bool dfs(int x){
if(vis[x]==Tim/*!!!*/) return false;//!!!
vis[x]=Tim;
for(int i=0,ss=medi[x].size();i<ss;i++) {
int v=medi[x][i]; if(vis[v]==Tim) continue;
if(!match[v] || dfs(match[v])) {
match[v]=x;
return true;
}
}
return false;
} inline void work(){
using namespace network;
n=getint(); Init(); int x,y;
for(int i=1;i<=n;i++) { x=getint(); while(x--) { y=getint(); medi[i].push_back(y+n); } }
for(int i=1;i<=n;i++) Tim++,dfs(i);
for(int i=1;i<=n;i++) P[i]=getint();
for(int i=1;i<=n;i++) for(int j=0,ss=medi[i].size();j<ss;j++) link(i,match[ medi[i][j] ],inf);
for(int i=1;i<=n;i++) {
P[i]=-P[i];
if(P[i]>0) link(S,i,P[i]),ans+=P[i];
else link(i,T,-P[i]);
} while(bfs())
ans-=dinic(S,inf); ans=-ans;
printf("%I64d",ans);
} int main()
{
#ifndef ONLINE_JUDGE
freopen("103.in","r",stdin);
freopen("103.out","w",stdout);
#endif
work();
return 0;
}
//有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
codeforces103E Buying Sets的更多相关文章
- CF 103E Buying Sets 最大权闭合子图,匹配 难度:4
http://codeforces.com/problemset/problem/103/E 这道题首先一看就很像是最大权闭合子图,但是我们可以认为现在有两种点,数字和集合点,我们需要消除数字点的影响 ...
- 【codeforces 103E】 Buying Sets
http://codeforces.com/problemset/problem/103/E (题目链接) 题意 给出$n$个数,每个数与一个集合相关联.从其中选出最小的若干个数,选出的数的个数与这些 ...
- TSQL 分组集(Grouping Sets)
分组集(Grouping Sets)是多个分组的并集,用于在一个查询中,按照不同的分组列对集合进行聚合运算,等价于对单个分组使用“union all”,计算多个结果集的并集.使用分组集的聚合查询,返回 ...
- grouping sets从属子句的运用
grouping sets主要是用来合并多个分组的结果. 对于员工目标业绩表'businessTarget': employeeId targetDate idealDistAmount 如果需要分别 ...
- Codeforces 722D. Generating Sets
D. Generating Sets time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- 【转】rollup、cub、grouping sets、grouping、grouping_id在报表中的应用
摘自 http://blog.itpub.net/26977915/viewspace-734114/ 在报表语句中经常要使用各种分组汇总,rollup和cube就是常用的分组汇总方式. 第一:gro ...
- salesforce 零基础学习(十九)Permission sets 讲解及设置
Permission sets以及Profile是常见的设置访问权限的方式. Profile规则为'who see what'.通过Profile可以将一类的用户设置相同的访问权限.对于有着相同Pro ...
- Python数据类型之“集合(Sets)与映射(Mapping)”
一.集合类型(Sets) 集合对象是不同的(不可重复)hashable对象的无序集合.常见用法包括:成员关系测试.移除序列中的重复.以及科学计算,例如交集.并集.差分和对称差分.通俗点来说,集合是一个 ...
- 【Swift学习】Swift编程之旅---集合类型之Sets(七)
Sets是存储无序的相同类型的值,你可以在顺序不重要的情况下使用Sets来替代数组,或者当你需要同一个值在集合中只出现一次时. 一.Sets类型语法 写作Set<Element>,Ele ...
随机推荐
- 22.Atomicity and Transactions-官方文档摘录
原子性和事务 1 在单个文档修改多个嵌入文档,写操作都在文档级别上都是原子的 2 在单个写操作修改多个文档时,每个文档的修改都具有原子性,但是,作为一个整体的操作,并不是原子的.其他操作可能有交互.使 ...
- 21.SQL to MongoDB Mapping Chart-官方文档摘录
有关关系型数据库跟Mongod的语法对比 In addition to the charts that follow, you might want to consider the Frequentl ...
- python 递归深度优先搜索与广度优先搜索算法模拟实现
一.递归原理小案例分析 (1)# 概述 递归:即一个函数调用了自身,即实现了递归 凡是循环能做到的事,递归一般都能做到! (2)# 写递归的过程 1.写出临界条件2.找出这一次和上一次关系3.假设当前 ...
- 批处理delims分割时遇到的问题。。
今天写了个将文件每行按逗号分割并取第六行的批处理.但是结果不对.看图一目了然. for 循环的/f 后面的参数是这样的 然后文件的内容是这样的 亮点是倒数第二行..其实6才是第六列的值.其他行第六列都 ...
- Mysql binlog 安全删除(转载)
简介: 如果你的 Mysql 搭建了主从同步 , 或者数据库开启了 log-bin 日志 , 那么随着时间的推移 , 你的数据库 data 目录下会产生大量的日志文件 shell > ll /u ...
- Vim step by step
@1: VIM中非常迷人的功能: D------->从当前位置开始删除,直到当前行结束 cw------->修改游标所在的单词,修改范围从游标位置到单词结尾. 一个替换一个用r,一个替换多 ...
- python 之操作redis数据库(非关系型数据库,k-v)
数据库: 1. 关系型数据库 表结构 2. 非关系型数据库 nosql (k - v 速度快),常用的时以下三种: memcache 存在内存里 redis 存在内存里 mangodb 数据还是存在磁 ...
- python全栈开发从入门到放弃之socket并发编程多线程
一 threading模块介绍 multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性,因而不再详细介绍 二 开启线程的两种方式 from threadi ...
- Django:学习笔记(9)——用户身份认证
Django:学习笔记(9)——用户身份认证 User
- Uninstalling JIRA applications from Linux
If you wish to re-install JIRA in 'unattended mode', do not uninstall your previous installation of ...