【bzoj2400】Spoj 839 Optimal Marks 二进制+最小割
来源:互联网 发布:java防止sql注入的方法 编辑:程序博客网 时间:2024/04/29 20:51
Description
定义无向图中的一条边的值为:这条边连接的两个点的值的异或值。
定义一个无向图的值为:这个无向图所有边的值的和。
给你一个有n个结点m条边的无向图。其中的一些点的值是给定的,而其余的点的值由你决定(但要求均为非负数),使得这个无向图的值最小。在无向图的值最小的前提下,使得无向图中所有点的值的和最小。
Input
第一行,两个数n,m,表示图的点数和边数。
接下来n行,每行一个数,按编号给出每个点的值(若为负数则表示这个点的值由你决定,值的绝对值大小不超过10^9)。
接下来m行,每行二个数a,b,表示编号为a与b的两点间连一条边。(保证无重边与自环。)
Output
第一行,一个数,表示无向图的值。第二行,一个数,表示无向图中所有点的值的和。
Sample Input
3 2 2 -1 0 1 2 2 3
Sample Output
2 2
HINT
数据约定
n<=500,m<=2000
样例解释
2结点的值定为0即可。
Source
二进制,按位处理。
首先%Oxer的题解
对于每一位单独处理。
每位只有两种可能:0或者1。所以可以把点集划分为两部分。考虑异或:相同为0,不同为1。也就是说只有两集合相邻部分会对答案有贡献,而我们的目标是贡献最小。
简单地说,就是把一个点集划分为两个集合,使它们相交部分贡献最小。这不就是最小割!
建模:源点向每个这位为0的点连INF边,这位为1的点向汇点连INF边。因为是无向图,所以原边
然而在顾及边权和最小时,没有顾及点权和最小。换句话说就是边权和一样的时候不一定保证点权和最小。贪心的想:若想要点权和最小,则s集合中的点一定尽量多,也就是说当最小割有多个的时候,选靠近汇点的那个割。
有一种方法是从汇点dfs,找到的点全部标为1。仔细想想好像没什么错,因为最靠近汇点的割也是割,它会阻碍汇点dfs到更多的点。
还有一种方法比较神…就是把刚刚说的建模的容量乘10000,也就是原边
这样求一遍最大流ans,对边权和贡献是ans/10000,对点权和是ans%10000。
这种思想简单来说就是扩大第一关键字的值,在第一关键字相同使考虑第二关键字,实现两种权值选优的目的。
#include<cstdio>#include<cstring>#include<iostream>#include<queue>#include<algorithm>using namespace std;typedef long long LL;const LL INF = 10000000000000000ll;const int SZ = 1000010;const LL mod = 10000;int head[SZ],nxt[SZ],tot = 1;struct edge{ int t; LL d;}l[SZ];void build(int f,int t,LL d){ l[++ tot].t = t; l[tot].d = d; nxt[tot] = head[f]; head[f] = tot;}void insert(int f,int t,LL d){ build(f,t,d); build(t,f,0);}int deep[SZ];queue<int> q;bool bfs(int s,int e){ memset(deep,0,sizeof(deep)); deep[s] = 1; while(q.size()) q.pop(); q.push(s); while(q.size()) { int u = q.front(); q.pop(); for(int i = head[u];i;i = nxt[i]) { int v = l[i].t; if(!deep[v] && l[i].d) { deep[v] = deep[u] + 1; q.push(v); if(v == e) return true; } } } return false;}LL dfs(int u,LL flow,int e){ if(e == u || flow == 0) return flow; LL rest = flow; for(int i = head[u];i;i = nxt[i]) { int v = l[i].t; if(deep[v] == deep[u] + 1 && l[i].d) { LL f = dfs(v,min(rest,l[i].d),e); if(f > 0) { l[i].d -= f; l[i ^ 1].d += f; rest -= f; if(rest == 0) break; } else deep[v] = 0; } } return flow - rest;}LL dinic(int s,int e){ LL ans = 0; while(bfs(s,e)) ans += dfs(s,INF,e); return ans;}int ff[SZ],tt[SZ],val[SZ],n,m;void init(){ tot = 1; memset(head,0,sizeof(head));}void build_graph(int x,int s,int e){ init(); for(int i = 1;i <= n;i ++) { insert(s,i,1); if(val[i] >= 0) { if(val[i] & (1 << x)) insert(i,e,INF); else insert(s,i,INF); } } for(int i = 1;i <= m;i ++) insert(ff[i],tt[i],mod),insert(tt[i],ff[i],mod);}int main(){ scanf("%d%d",&n,&m); for(int i = 1;i <= n;i ++) scanf("%d",&val[i]); for(int i = 1;i <= m;i ++) scanf("%d%d",&ff[i],&tt[i]); int s = n + 1,e = n + 2; LL ans1 = 0,ans2 = 0; for(int i = 30;i >= 0;i --) { build_graph(i,s,e); LL sum = dinic(s,e); ans1 += sum / mod * (1ll << i); ans2 += sum % mod * (1ll << i); } printf("%lld\n%lld",ans1,ans2); return 0;}
- 【bzoj2400】Spoj 839 Optimal Marks 二进制+最小割
- 【bzoj2400】Spoj 839 Optimal Marks 最小割
- [bzoj2400]Spoj 839 Optimal Marks 最小割
- [BZOJ2400]Spoj 839 Optimal Marks(最小割)
- BZOJ2400:[Spoj 839]Optimal Marks(最小割)
- BZOJ2400 Spoj 839 Optimal Marks
- BZOJ2400: Spoj 839 Optimal Marks
- SPOJ 839 Optimal Marks 最小割
- 【SPOJ】839 Optimal Marks 最小割
- 2400: Spoj 839 Optimal Marks 最小割
- SPOJ Optimal Marks 最小割
- SPOJ 839 Optimal Marks 最小割 经典 按位建图
- spoj 839 OPTM - Optimal Marks(最小割应用)
- 【 bzoj 2400 】Spoj 839 Optimal Marks - 最小割
- BZOJ 2400: Spoj 839 Optimal Marks|最小割
- bzoj 2400: Spoj 839 Optimal Marks (最小割)
- spoj 839 OPTM - Optimal Marks (最小割)
- [最小割] BZOJ 2400 Spoj 839 Optimal Marks
- 05.自定义瀑布流
- 设计模式学前准备
- JS 表单数据封装到后台的工具类
- ARM指令与Thumb指令的区别及常用ARM指令格式
- ApplePay接入
- 【bzoj2400】Spoj 839 Optimal Marks 二进制+最小割
- Natapp--- 基于ngrok 免费的高速内网穿透服务
- 创建你的第一个SSIS项目
- Java修饰符
- zook安装手册
- iOS内存优化-初级初级初级初级技巧
- 元素的长度值
- 深入理解Java:注解(Annotation)基本概念
- ArcGIS中使用工具后,没有反应,没有结果文件生成的问题解决办法。