zoukankan      html  css  js  c++  java
  • BZOJ 3275: Number( 最小割 )

    S->每个奇数,每个偶数->T各连一条边, 容量为这个数字.然后不能同时选的两个数连容量为+oo的边. 总数-最大流即是答案.

    因为满足a2+b2=c2的a,b一定是一奇一偶或者两个偶数, 2偶不满足gcd=1, 所以两个数不能同时选一定是一奇一偶.

    ---------------------------------------------------------------------

    #include<bits/stdc++.h>
     
    using namespace std;
     
    typedef long long ll;
     
    const int maxn = 3009;
    const int INF = 0x7FFFFFFF;
     
    struct edge {
    int to, cap;
    edge *next, *rev;
    } E[1000000], *pt = E, *head[maxn];
     
    inline void add(int u, int v, int w) {
    pt->to = v; pt->cap = w; pt->next = head[u]; head[u] = pt++;
    }
    inline void addedge(int u, int v, int w) {
    add(u, v, w); add(v, u, 0);
    head[u]->rev = head[v];
    head[v]->rev = head[u];
    }
     
    edge *cur[maxn], *p[maxn];
    int h[maxn], cnt[maxn], S, T, N;
     
    int maxFlow() {
    memset(cnt, 0, sizeof cnt);
    memset(h, 0, sizeof h);
    cnt[0] = N;
    edge* e;
    int flow = 0;
    for(int x = S, A = INF; h[S] < N; ) {
    for(e = cur[x]; e; e = e->next)
    if(e->cap && h[e->to] + 1 == h[x]) break;
    if(e) {
    p[e->to] = cur[x] = e;
    A = min(e->cap, A);
    x = e->to;
    if(x == T) {
    for(; x != S; x = p[x]->rev->to) {
    p[x]->cap -= A;
    p[x]->rev->cap += A;
    }
    flow += A;
    A = INF;
    }
    } else {
    if(!--cnt[h[x]]) break;
    h[x] = N;
    for(e = head[x]; e; e = e->next) if(e->cap && h[e->to] + 1 < h[x]) {
    cur[x] = e;
    h[x] = h[e->to] + 1;
    }
    cnt[h[x]]++;
    if(x != S) x = p[x]->rev->to;
    }
    }
    return flow;
    }
     
    int num[maxn];
     
    int gcd(int x, int y) {
    return y ? gcd(y, x % y) : x;
    }
     
    bool check(int x, int y) {
    int h = gcd(x, y);
    if(h != 1) return false;
    ll t = ll(x) * x + ll(y) * y;
    t = (ll)sqrt(t);
    if(t * t == ll(x) * x + ll(y) * y) return true;
    return false;
    }
     
    int main() {
    int n; scanf("%d", &n);
    int tot = 0;
    S = 0; T = n + 1; N = T + 1;
    for(int i = 1; i <= n; i++) {
    scanf("%d", num + i);
    tot += num[i];
    num[i] & 1 ? addedge(S, i, num[i]) : addedge(i, T, num[i]);
    }
    for(int i = 1; i <= n; i++) if(num[i] & 1)
    for(int j = 1; j <= n; j++) if(!(num[j] & 1))
    if(check(num[i], num[j])) addedge(i, j, INF);
    printf("%d ", tot - maxFlow());
    return 0;
    }

    ---------------------------------------------------------------------

    3275: Number

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 504  Solved: 222
    [Submit][Status][Discuss]

    Description

    有N个正整数,需要从中选出一些数,使这些数的和最大。
    若两个数a,b同时满足以下条件,则a,b不能同时被选
    1:存在正整数C,使a*a+b*b=c*c
    2:gcd(a,b)=1

    Input

    第一行一个正整数n,表示数的个数。
    第二行n个正整数a1,a2,?an。
     
     

    Output

    最大的和。
     

    Sample Input

    5
    3 4 5 6 7



    Sample Output

    22


    HINT

    n<=3000。

    Source

  • 相关阅读:
    ubuntu下按安装lamp
    linux 一些简记
    编写shell脚本步骤
    C++ array vector 数组
    抓取网页扒图片相对路径改绝对路径
    静态html文件js读取url参数
    IE7的web标准之道——1:前言(兼目录) (很牛的CSS书籍)
    感谢放逐自由《博客园精华集》分类索引
    这篇文章证实了索引对于IN,LIKE的优化程度,顺便学会了怎么看看语耗费的时间
    命名空间“System”中不存在类型或命名空间名称“Linq”(是缺少程序集引用吗?)
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/4838155.html
Copyright © 2011-2022 走看看