BZOJ2400 Spoj 839 Optimal Marks

首先发现每一位二进制可以分开来做。

然后就变成0、1两种数了,考虑最小割。

设S表示选0,T表示选1,则

对于确定的点向数字对应的S/T连边,边权inf;然后原来图中有边的,互相连边,边权为1。

直接最小割即可,最后还要dfs一下来求出每个未确定的数选的是0还是1。

  1 /**************************************************************
  2     Problem: 2400
  3     User: rausen
  4     Language: C++
  5     Result: Accepted
  6     Time:552 ms
  7     Memory:3180 kb
  8 ****************************************************************/
  9
 10 #include <cstdio>
 11 #include <cstring>
 12 #include <algorithm>
 13
 14 using namespace std;
 15 typedef long long ll;
 16 const int N = 505;
 17 const int M = 2005;
 18 const int Me = 200005;
 19 const int inf = 1e9;
 20
 21 struct edge {
 22     int x, y;
 23     edge() {}
 24     edge(int _x, int _y) : x(_x), y(_y) {}
 25 } E[M];
 26
 27 struct edges {
 28     int next, to, f;
 29     edges() {}
 30     edges(int _n, int _t, int _f) : next(_n), to(_t), f(_f) {}
 31 } e[Me];
 32
 33 int n, m, S, T;
 34 int a[N], del[N];
 35 int tot, first[N];
 36 int d[N], q[N];
 37 ll ans;
 38
 39 inline int read() {
 40     int x = 0, sgn = 1;
 41     char ch = getchar();
 42     while (ch < ‘0‘ || ‘9‘ < ch) {
 43         if (ch == ‘-‘) sgn = -1;
 44         ch = getchar();
 45     }
 46     while (‘0‘ <= ch && ch <= ‘9‘) {
 47         x = x * 10 + ch - ‘0‘;
 48         ch = getchar();
 49     }
 50     return sgn * x;
 51 }
 52
 53 inline void Add_Edges(int x, int y, int f) {
 54     e[++tot] = edges(first[x], y, f), first[x] = tot;
 55     e[++tot] = edges(first[y], x, 0), first[y] = tot;
 56 }
 57
 58 bool bfs() {
 59     int l, r, x, y;
 60     memset(d, 0, sizeof(d));
 61     d[q[1] = S] = 1;
 62     for (l = r = 1; l != (r + 1) % N; (++l) %= N)
 63         for (x = first[q[l]]; x; x = e[x].next)
 64             if (!d[y = e[x].to] && e[x].f)
 65                 d[q[(++r) %= N] = y] = d[q[l]] + 1;
 66     return d[T];
 67 }
 68
 69 int dfs(int p, int lim) {
 70     if (p == T || !lim) return lim;
 71     int x, y, tmp, rest = lim;
 72     for (x = first[p]; x; x = e[x].next)
 73         if (d[y = e[x].to] == d[p] + 1 && (tmp = min(e[x].f, rest) > 0)) {
 74             rest -= (tmp = dfs(y, tmp));
 75             e[x].f -= tmp, e[x ^ 1].f += tmp;
 76             if (!rest) return lim;
 77         }
 78     if (lim == rest) d[p] = 0;
 79     return lim - rest;
 80 }
 81
 82 int Dinic() {
 83     int res = 0;
 84     while (bfs())
 85         res += dfs(S, inf);
 86     return res;
 87 }
 88
 89 void build_graph(int t) {
 90     int i;
 91     tot = 1, memset(first, 0, sizeof(first));
 92     for (i = 1; i <= n; ++i)
 93         if (a[i] >= 0)
 94             if (a[i] & t) Add_Edges(i, T, inf);
 95             else Add_Edges(S, i ,inf);
 96     for (i = 1; i <= m; ++i)
 97         Add_Edges(E[i].x, E[i].y, 1), Add_Edges(E[i].y, E[i].x, 1);
 98 }
 99
100 void find(int p) {
101     int x, y;
102     d[p] = 1;
103     for (x = first[p]; x; x = e[x].next)
104         if (e[x ^ 1].f && !d[y = e[x].to]) find(y);
105 }
106
107 void calc_val(int t) {
108     int i;
109     memset(d, 0, sizeof(d));
110     find(T);
111     for (i = 1; i <= n; ++i)
112         if (d[i]) del[i] += t;
113 }
114
115 ll calc_ans() {
116     ll res = 0;
117     int i;
118     for (i = 1; i <= n; ++i)
119         res += a[i] >= 0 ? a[i] : del[i];
120     return res;
121 }
122
123 int main() {
124     int i;
125     n = read(), m = read();
126     S = n + 1, T = n + 2;
127     for (i = 1; i <= n; ++i)
128         a[i] = read();
129     for (i = 1; i <= m; ++i)
130         E[i] = edge(read(), read());
131     for (i = 0; i <= 30; ++i) {
132         build_graph(1 << i);
133         ans += (ll) (1 << i) * Dinic();
134         calc_val(1 << i);
135     }
136     printf("%lld\n%lld\n", ans, calc_ans());
137     return 0;
138 }

时间: 2024-10-20 01:20:49

BZOJ2400 Spoj 839 Optimal Marks的相关文章

SPOJ 839 Optimal Marks 最小割 经典 按位建图

胡伯涛论文中的一题,经典建模,由于二进制每一位异或不会相互影响,所以我们把问题转换模型,按位处理. 即已知一些点的标号0/1(还有些可以自己任意改),和一些边,边权定义为两端点标号的异或,要求边权和最小的标号方案. 我们联想到最小割求的是从源到汇容量最小的边权和. 建图: 标号为1的和源点相连,容量INF,标号为0的和汇点相连,容量INF,这些边是不能割掉的(这些点标号已经明确) 原图相连的边,连边,容量为1.(若将此边割掉,则两端点一个为0,一个为1,割为1) 跑完最大流后,在残量网络中dfs

图论(网络流):SPOJ OPTM - Optimal Marks

OPTM - Optimal Marks You are given an undirected graph G(V, E). Each vertex has a mark which is an integer from the range [0..231 – 1]. Different vertexes may have the same mark. For an edge (u, v), we define Cost(u, v) = mark[u] xor mark[v]. Now we

SPOJ OPTM Optimal Marks

Optimal Marks Time Limit: 6000ms Memory Limit: 262144KB This problem will be judged on SPOJ. Original ID: OPTM64-bit integer IO format: %lld      Java class name: Main You are given an undirected graph G(V, E). Each vertex has a mark which is an inte

SPOJ Optimal Marks(最小割的应用)

SPOJ Optimal Marks(最小割的应用) 真心好题,网络流简直无处不在,能够解决一些看似困难的问题,希望能从中学到其精髓--模型建立+建图 题意: 给定一个无向图,每个顶点都有对应值,每条边的权值为val[u] ^ val[u],同时已知其中某些点的值,求其他点的权值使得最终的图的边权和最小? 分析: 首先边与边之间异或操作,不太好直接处理,因为异或操作每一位运算相互独立,我们来逐位考虑,那么对于那些还未知的权值的点,这一位要么为0 ,要么为1,同时我们还得注意边的两个端点值相同则没

[SPOJ839]Optimal Marks

[SPOJ839]Optimal Marks 试题描述 You are given an undirected graph \(G(V, E)\). Each vertex has a mark which is an integer from the range \([0..2^{31} - 1]\). Different vertexes may have the same mark. For an edge \((u, v)\), we define \(Cost(u, v) = mark

SP839 Optimal marks(最小割)

SP839 Optimal marks(最小割) 给你一个无向图G(V,E). 每个顶点都有一个int范围内的整数的标记. 不同的顶点可能有相同的标记.对于边(u,v),我们定义Cost(u,v)= mark [u] \(\oplus\) mark [v].现在我们知道某些节点的标记了.你需要确定其他节点的标记,以使边的总成本尽可能小.(0 < N <= 500, 0 <= M <= 3000) 先来看一下异或的性质,由于每一位是独立的,我们可以把每一位拉出来分开考虑,变成32个子

SPOJ839 OPTM - Optimal Marks

传送门 闵神讲网络流应用的例题,来水一水 要写出这道题,需要深入理解两个概念,异或和最小割. 异或具有相对独立性,所以我们把每一位拆开来看,即做大概$32$次最小割.然后累加即可. 然后是最小割把一张图分割成两个集合,简单看就是0集合和1集合. 简单的建图: 原图不变,改成双向边,所有的流量限制为1.然后所有S点向点权为1的连边,点权为0的向T连边,容量都是正无穷. 为什么这样建?首先看,最小割把一张图分成两个点集.而因为我们的流量限制可以让最小割只割真实存在的边,而割的也只有可能是跨越0集合和

SPOJ839 Optimal Marks(最小割)

题目大概说给一张图,每个点都有权,边的权等于其两端点权的异或和,现已知几个点的权,为了使所有边的边权和最小,其他点的权值该是多少. 很有意思的一道题,完全看不出和网络流有什么关系. 考虑每个未知的点$x$的权的二进制的第$i$位$x_i$,其对边权和的贡献为$\sum_{(x,y)\in E}(2^i\cdot(x_i\ \hat{}\ y_i))=2^i\sum_{(x,y)\in E}(x_i\ \hat{}\ y_i)$,而$x_i$取值是$0$或$1$! 这样问题就明了了: 相当于对于每

BZOJ 2400 Optimal Marks 最小割

题目大意:给定一个无向图,一些点有权值,其它点的权值可以自己指定,要求指定这些点的权值,使每条边两边的点权异或值之和最小 在此基础上要求点权和最小 首先不考虑点权和最小这个条件 那么我们将每一位分开计算 我们会发现这是一个最小割的模型 令S集为0,T集为1,如果这个点的点权已经指定,则向相应集合连流量为INF的边 每条边的两端点之间连一条流量为1的边 跑最小割就是答案 现在我们将点权考虑进去 将原图每条边的流量扩大10000倍 如果一个点和S没有连边,就从S向这个点连一条流量为1的边 这样如果和