博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【CF311E】biologist
阅读量:6578 次
发布时间:2019-06-24

本文共 2546 字,大约阅读时间需要 8 分钟。

题目大意

简述一下:
有n个布尔变量,开始时分别是0或1。你可以改变这些变量,改变(0变1,1变0)第i个变量的代价是v[i]
现在有m个限制,形如a,b,x1,x2,x3…,xk,表示希望x1-xk都是a(a为0或1),都满足后可以获得b的价值
有一些限制如果没有满足要倒扣g的价值,g对于所有限制是一个相同的值
求最后能获得的最大价值

思路

一眼网络流

一个错误的思路:假设我们只考虑1,那么每个人到s连边,每个人到ta希望是1的连边,每个1(如果要改)向t连边。总和减最小割。但是这样无法考虑1和0。考虑使得1和0不能同时选(也不能同时不选),于是不能都不割,也不能都割,所以把是1和是0作为两个点,使他们在一个路径上。这样无法表示不满足某个限制。
想不粗来了qwq
于是注意到我们有一些条件没有用:每个限制一定是某些全是1/全是0,于是其实限制是两类
那么把变量放中间,希望是1的限制放在上面连s,希望是0的放下面连t,每个和他所限制的变量连边,这样可以保证每个点所构成的通路一定是一边(上边/下边)都被割了,这样可以表示最终是1/0
现在最后考虑改变变量的代价:假设这个变量最开始是1,那么我们希望这个代价是加在他不是1上的,就是加在他割去表示1那边的时候。那么我们让他割去1之后仍然联通,于是把他跟1那边的虚拟点联通(1的话就是s)。
于是我们解决了这个问题

总结

此题解法可以类比如何使得两个东西不能同时选,不能同时不选

注意观察题目是否有隐藏性质没有使用

代码

#include 
#include
#include
#include
#include
#include
#include
#include
#define MAXN 10050#define INF (1<<28)using namespace std;int s, t, n, m, g, sex[MAXN], v[MAXN], ans, level[MAXN<<3], q[MAXN<<3], cnt;struct node{ int v, c; node *next, *rev;}pool[MAXN<<6], *h[MAXN<<4], *cur[MAXN<<4];inline void addedge(int u, int v, int c){ node *p1 = &pool[cnt++], *p2 = &pool[cnt++]; *p1 = node{v, c, h[u], p2}, h[u] = p1; *p2 = node{u, 0, h[v], p1}, h[v] = p2;}// s 0 t 1bool bfs(){ int front = 0, rear = 1; memset(level, 0, sizeof(level)); level[s] = 1; q[0] = s; while(front < rear){ int u = q[front++]; if(u == t) return 1; for(node *p = h[u]; p; p = p->next){ if(!level[p->v] && p->c){ q[rear++] = p->v; level[p->v] = level[u]+1; } } } return 0;}int dfs(int u, int t, int f){ if(u == t) return f; int flow = 0, F, Min; for(node *&p = cur[u]; p; p = p->next){ if(level[p->v] == level[u]+1 && p->c){ Min = min(f-flow, p->c); F = dfs(p->v, t, Min); flow += F; p->c -= F; p->rev->c += F; if(flow == f) return flow; } } return flow;}int Dinic(){ int ret = 0; while(bfs()){ for(int i = s; i <= t; i++) cur[i] = h[i]; ret += dfs(s, t, INF); } return ret;}int main(){ scanf("%d%d%d", &n, &m, &g); t = n+m+1; int w, k, exp, fri, cur; for(int i = 1; i <= n; i++) scanf("%d", &sex[i]); for(int i = 1; i <= n; i++) scanf("%d", &v[i]); for(int i = 1; i <= m; i++) { scanf("%d%d%d", &exp, &w, &k); ans += w; for(int j = 1; j <= k; j++) { scanf("%d", &cur); if(exp) addedge(cur+m, i, INF); else addedge(i, cur+m, INF); } scanf("%d", &fri); w += g*fri; if(exp) addedge(i, t, w); else addedge(s, i, w); } for(int i = 1; i <= n; i++) { if(sex[i]) addedge(i+m, t, v[i]); else addedge(s, i+m, v[i]); } int cut = Dinic(); //cout<
<<' '; ans -= cut; printf("%d", ans); return 0;}

转载于:https://www.cnblogs.com/hychyc/p/9727468.html

你可能感兴趣的文章
什么是企业内训
查看>>
firefox无法显示java插件plugin
查看>>
Windows Phone 7 自定义弹出窗口
查看>>
H3C设备之OSPF DR选举
查看>>
java reflection singleton factorypattern
查看>>
View控件Edittext属性
查看>>
List grantee right in oracle
查看>>
骨牌铺方格 ——解题报告
查看>>
Training 的第一天
查看>>
Activity生命周期
查看>>
通过VBS编写自动输入账号和密码、自动登录程序的脚本
查看>>
MTK APSoC SDK MT7621编译固件的快速开始
查看>>
【Hibernate】Hibernate.cfg.xml配置文件详解
查看>>
关于KMP算法的学习
查看>>
异步函数及Node事件循环
查看>>
delete select 表
查看>>
2. composer的简单操作
查看>>
maven setting
查看>>
二叉树中和为某一值的路径
查看>>
Android 应用语言设置的实现
查看>>