您的位置:首页 > 其它

BZOJ2661 [BeiJing wc2012]连连看

2014-12-21 17:18 381 查看
把每个数拆成两个点建图

具体原因我想了想。。。因为一个点一定是不能做的。。。但是两个点不能保证一定是对称流法啊。。。(坑)

如果两个数a, b满足要求,则a -> b', b -> a',边流量为1,费用为- a - b

最后再建源汇S, T,分别连边,流量为1,费用为0

跑一边费用流即可,但是要记下流量

/**************************************************************
Problem: 2661
User: rausen
Language: C++
Result: Accepted
Time:128 ms
Memory:3984 kb
****************************************************************/

#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;
const int N = 2005;
const int M = N * 100;
const int inf = (int) 1e9;

struct edges {
int next, to, f, cost;
edges() {}
edges(int _n, int _t, int _f, int _c) : next(_n), to(_t), f(_f), cost(_c) {}
} e[M];

int n, S, T;
int first
, tot = 1;
int d
, g
, q
;
bool v
;

inline void Add_Edges(int x, int y, int f, int c) {
e[++tot] = edges(first[x], y, f, c), first[x] = tot;
e[++tot] = edges(first[y], x, 0, -c), first[y] = tot;
}

inline int calc() {
int flow = inf, x;
for (x = g[T]; x; x = g[e[x ^ 1].to])
flow = min(flow, e[x].f);
for (x = g[T]; x; x = g[e[x ^ 1].to])
e[x].f -= flow, e[x ^ 1].f += flow;
return flow;
}

bool spfa() {
int x, y, l, r;
for (x = 1; x <= T; ++x)
d[x] = inf;
d[S] = 0, v[S] = 1, q[0] = S;
for(l = r = 0; l != (r + 1) % N; ++l %= N) {
for (x = first[q[l]]; x; x = e[x].next)
if (d[q[l]] + e[x].cost < d[y = e[x].to] && e[x].f) {
d[y] = d[q[l]] + e[x].cost, g[y] = x;
if (!v[y])
q[++r %= N] = y, v[y] = 1;
}
v[q[l]] = 0;
}
return d[T] != inf;
}

inline void work() {
int ans1 = 0, ans2 = 0, del;
while (spfa()) {
del = calc();
ans1 += del, ans2 += del * d[T];
}
printf("%d %d\n", ans1 >> 1, -ans2 >> 1);
}

inline int sqr(int x) {
return x * x;
}

inline int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}

inline bool check(int a, int b) {
int t = sqr(b) - sqr(a);
if (sqr((int) sqrt(t)) != t) return 0;
return gcd(a, (int) sqrt(t)) == 1;
}

int main() {
int a, b, i, j;
scanf("%d%d", &a, &b);
S = (b - a + 1) << 1 | 1, T = S + 1;
for (i = a; i <= b; ++i)
for (j = a; j < i; ++j) if (check(j, i))
Add_Edges(i - a + 1, j + b - a * 2 + 2, 1, - i - j),
Add_Edges(j - a + 1, i + b - a * 2 + 2, 1, - i - j);
for (i = a; i <= b; ++i)
Add_Edges(S, i - a + 1, 1, 0), Add_Edges(i + b - a * 2 + 2, T, 1, 0);
work();
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: