您的位置:首页 > 理论基础 > 计算机网络

ZOJ 3760 - Treasure Hunting(网络流‘最小割’最大点权独立集)

2015-10-05 22:37 507 查看
题目:

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3760

题意:

有n个点,每个点的价值是x&y,求出一个集合,使得集合中任意两点之间的 gcd(xi^yi^xj^yj, p)> 1。求出集合的最大点权。

思路:

要使得别人与自己的公约数不为1.则p必定为偶数。两个点的异或值都为偶数则异或为偶数,两个点的异或值都为奇数则异或为偶数,只有当一个点异或值为偶数一个点异或值为奇数的情况下不确定,则可以根据异或值的奇偶性将二分图。最小割求出最小点权覆盖,答案为最大点权独立集 = sum - 最小点权覆盖。

点覆盖集V:满足存在(u, v)边,u和v至少有一个点在V中。

点独立集V:满足存在(u,v)边,u和v仅有一个点在V中。

AC.

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>

using namespace std;
typedef long long ll;
const ll inf = 1e16;
const ll maxm = 505*505;
const ll maxn = 1010;

ll vor[maxn], vand[maxn];

ll tot, head[maxn];
struct Edge{
ll to, next;
ll cap, flow;
}edge[maxm*4];
void addedge(ll u, ll v, ll w)
{
edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = 0;
edge[tot].next = head[u]; head[u] = tot++;

edge[tot].to = u; edge[tot].cap = 0; edge[tot].flow = 0;
edge[tot].next = head[v]; head[v] = tot++;
}

ll Q[maxn];
ll gap[maxn], dep[maxn], cur[maxn];
void bfs(ll s, ll t)
{
memset(dep, -1, sizeof(dep));
memset(gap, 0, sizeof(gap));
gap[0] = 1;

ll fron = 0, rea = 0;
dep[t] = 0;
Q[rea++] = t;

while(fron != rea) {
ll u = Q[fron++];
for(ll i = head[u]; ~i; i = edge[i].next) {
ll v = edge[i].to;
if(dep[v] != -1) continue;
Q[rea++] = v;
dep[v] = dep[u] + 1;
gap[dep[v]]++;
}
}
}
ll S[maxn];
ll sap(ll s, ll t, ll N)
{
bfs(s, t);
memcpy(cur, head, sizeof(head));
ll top = 0;
ll u = s;
ll ans = 0;
while(dep[s] < N) {
if(u == t) {
ll Min = inf;
ll inser;
for(ll i = 0; i < top; ++i) {
if(Min > edge[S[i]].cap - edge[S[i]].flow) {
Min = edge[S[i]].cap - edge[S[i]].flow;
inser = i;
}
}
for(ll i = 0;i < top; ++i) {
edge[S[i]].flow += Min;
edge[S[i]^1].flow -= Min;
}
ans += Min;
top = inser;
u = edge[S[top]^1].to;
continue;
}

bool flag = 0;
ll v;
for(ll i = cur[u]; ~i; i = edge[i].next) {
v = edge[i].to;
if(edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u]) {
flag = true;
cur[u] = i;
break;
}
}
if(flag) {
S[top++] = cur[u];
u = v;
continue;
}
ll Min = N;
for(ll i = head[u]; ~i; i = edge[i].next) {
if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) {
Min = dep[edge[i].to];
cur[u] = i;
}
}

gap[dep[u]]--;
if(!gap[dep[u]]) return ans;
dep[u] = Min + 1;
gap[dep[u]]++;
if(u != s) u = edge[S[--top]^1].to;
}
return ans;
}

void init()
{
tot = 0;
memset(head, -1, sizeof(head));
}

ll gcd(ll a, ll b)
{
return b == 0? a: gcd(b, a%b);
}

int main()
{
//freopen("in", "r", stdin);
ll n, p;
while(~scanf("%lld%lld", &n, &p)) {
init();
ll sum = 0;
ll s = 0, t = n+1;
for(ll i = 1; i <= n; ++i) {
ll x, y;
scanf("%lld%lld", &x, &y);
vor[i] = x^y;
ll c = x&y;
if(vor[i] % 2 == 0) addedge(s, i, c);
else addedge(i, t, c);
sum += c;
}
for(ll i = 1; i <= n; ++i) {
for(ll j = i+1; j <= n; ++j) {
if(gcd(vor[i]^vor[j], p) == 1) {
if(vor[i]%2 == 0 && vor[j]%2 == 1) addedge(i, j, inf);
else if(vor[i]%2 == 1 && vor[j]%2 == 0) addedge(j, i, inf);
}
}
}

ll res = sap(s, t, t+1);
printf("%lld\n", sum-res);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ZOJ