题面
一个无向图,一些点有固定权值,另外的点权值由你来定.
边的值为两点的异或值,一个无向图的值定义为所有边的值之和.
求无向图的最小值
分析
每一位都互不干扰,按位处理.
用最小割算最小值
- 保留原图的边,容量为1
- 如果当前点这一位是1,就从S连向当前点,容量为
- 如果当前点这一位是0,就从当前点连向T,容量为
那么这样一来,分在S一边就表示选,分在T一边就表示不选.如果相邻的两点在不同的集合,中间的边就必须断掉,造成1的代价,那么刚好相当于中间的边的值.
跑一遍最小割然后从S开始搜,不搜满流的边(也就是被割开的边),加上答案即可
- 对于在边值相等的情况下,要求点值最小的正确性如下:
在我们的最小割中,被划分在S一边表示选,那么一条增广路径上有多条满流边的时候,我们的搜索处理方法是遇到满流边就不往下走.所以我们割的边一定最靠近S集,也就是尽量地多让剩下点被分在T集(也就是选0),这样就满足了在同等情况下尽量选0使得点值最小. - 另一种方法是把边值设为10000,点值设为1.那么最小边值之和就是ans/10000,在此情况下的最小点值就是ans%10000
CODE
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long LL;
template<typename T>inline void read(T &num) {
char ch; int flg=1;
while((ch=getchar())<'0'||ch>'9')if(ch=='-')flg=-flg;
for(num=0;ch>='0'&&ch<='9';num=num*10+ch-'0',ch=getchar());
num*=flg;
}
const int inf = 1e9;
const int MAXN = 505;
const int MAXM = 20005;
int n, m, fir[MAXN], S, T, cnt;
struct edge { int to, nxt; LL c; }e[MAXM];
inline void add(int u, int v, LL cc, LL rc=0) {
e[cnt] = (edge){ v, fir[u], cc }; fir[u] = cnt++;
e[cnt] = (edge){ u, fir[v], rc }; fir[v] = cnt++;
}
int dis[MAXN], vis[MAXN], info[MAXN], cur, q[MAXN];
inline bool bfs() {
int head = 0, tail = 0;
vis[S] = ++cur; q[tail++] = S;
while(head < tail) {
int u = q[head++];
for(int i = fir[u]; ~i; i = e[i].nxt)
if(e[i].c && vis[e[i].to] != cur)
vis[e[i].to] = cur, dis[e[i].to] = dis[u] + 1, q[tail++] = e[i].to;
}
if(vis[T] == cur) memcpy(info, fir, (T+1)<<2);
return vis[T] == cur;
}
LL dfs(int u, LL Max) {
if(u == T || !Max) return Max;
LL flow=0, delta;
for(int &i = info[u]; ~i; i = e[i].nxt)
if(e[i].c && dis[e[i].to] == dis[u] + 1 && (delta=dfs(e[i].to, min(e[i].c, Max-flow)))) {
e[i].c -= delta, e[i^1].c += delta, flow += delta;
if(flow == Max) return flow;
}
return flow;
}
inline LL dinic() {
memset(vis, 0, sizeof vis);
LL flow=0, x;
while(bfs()) {
while((x=dfs(S, inf))) flow+=x;
}
return flow;
}
int A[MAXN], X[2005], Y[2005]; LL ans1, ans2;
bool flg[MAXN];
void Getans2(int u, int val) {
if(u) ans2 += val; flg[u] = 1;
for(int i = fir[u]; ~i; i = e[i].nxt)
if(e[i].c && !flg[e[i].to])
Getans2(e[i].to, val);
}
int main () {
read(n); read(m); S = 0, T = n+1;
for(int i = 1; i <= n; ++i) read(A[i]);
for(int i = 1; i <= m; ++i) read(X[i]), read(Y[i]);
for(int bit = 0; bit < 30; ++bit) {
memset(fir, -1, sizeof fir); cnt = 0;
for(int i = 1; i <= m; ++i) add(X[i], Y[i], 1, 1);
for(int i = 1; i <= n; ++i) {
if(A[i] < 0) continue;
if(A[i]&(1<<bit)) add(S, i, inf);
else add(i, T, inf);
}
memset(flg, 0, sizeof flg);
ans1 += dinic() * (1<<bit);
Getans2(S, 1<<bit);
}
printf("%lld
%lld
", ans1, ans2);
}
不开毁一生