bzoj3158 千钧一发

来源:互联网 发布:visual studio mac版 编辑:程序博客网 时间:2024/05/17 23:19

bzoj3158 千钧一发

Description
1
Input

第一行一个正整数N。

第二行共包括N个正整数,第 个正整数表示Ai。

第三行共包括N个正整数,第 个正整数表示Bi。

Output

共一行,包括一个正整数,表示在合法的选择条件下,可以获得的能量值总和的最大值。

Sample Input

4
3 4 5 12
9 8 30 9

Sample Output

39

HINT

1<=N<=1000,1<=Ai,Bi<=10^6

这道题也是一道很好的题啊.. 值得去想一想

因为题目要求我们求最大值,那我们就想,能不能把它转化成总和减去损失的最小值呢?对了,就是最小割

首先我们先想一下一个割边的模型,也就是每个点连源连汇,然后割掉其中一条边表示选这个点进入集合所损失的价值,割掉另一条边表示不选这个点进入集合所损失的价值

又由于两个点是会因为某些条件不能在同一个集合中,所以我们要这样建边:
如下:
这里写图片描述

请注意,中间这一条边是单向边而不是各位认为的双向边

假如两个点都割【选】的边,那么肯定会存在有某个点割【不选】的边使得这种方案的最小割比当前的优,因为存在一条【不选】->【inf】->【不选】的增广路。但是,如果我现在割掉两个【不选】的边,并没有什么关系啊..

那么你也许会问,这个东西保证是二分图吗。那我下面给出证明咯
1.假如两个点都为偶数,那么他们满足第二个条件
2.加入两个点都为奇数,那么他们满足第一个条件
至于为什么,自己好好想想

所以就酱紫咯..

#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <queue>#include <cmath>#define LL long longusing namespace std;const int Maxn = 1100;const int inf = 0x7fffffff;struct node {    int x, y, next, c, opp;}a[Maxn*Maxn*5]; int first[Maxn], len;int _min ( int x, int y ){ return x < y ? x : y; }void ins ( int x, int y, int c ){    len ++; int k1 = len;    a[len].x = x; a[len].y = y; a[len].c = c;    a[len].next = first[x]; first[x] = len;    len ++; int k2 = len;    a[len].x = y; a[len].y = x; a[len].c = 0;    a[len].next = first[y]; first[y] = len;    a[k1].opp = k2;    a[k2].opp = k1;}int st, ed, h[Maxn];int n;int na[Maxn];int gcd ( int a, int b ){    if ( a == 0 ) return b;    return gcd ( b%a, a );}bool check ( int x, int y ){    LL ph = (LL)x*x+(LL)y*y;    LL kf = sqrt (ph);    if ( kf*kf != ph ) return false;    if ( gcd ( x, y ) == 1 ) return true;    else return false;}bool bfs (){    queue <int> q;    memset ( h, -1, sizeof (h) );    q.push (st); h[st] = 0;    while ( !q.empty () ){        int x = q.front (); q.pop ();        for ( int k = first[x]; k; k = a[k].next ){            int y = a[k].y;            if ( h[y] == -1 && a[k].c > 0 ){                h[y] = h[x]+1;                q.push (y);            }        }    }    return h[ed] > 0;}int dfs ( int x, int flow ){    if ( x == ed ) return flow;    int delta = 0;    for ( int k = first[x]; k; k = a[k].next ){        int y = a[k].y;        if ( h[y] == h[x]+1 && a[k].c > 0 && flow-delta > 0 ){            int minf = dfs ( y, _min ( a[k].c, flow-delta ) );            delta += minf;            a[k].c -= minf;            a[a[k].opp].c += minf;        }    }    if ( delta == 0 ) h[x] = -1;    return delta;}int main (){    int i, j, k;    scanf ( "%d", &n );    for ( i = 1; i <= n; i ++ ) scanf ( "%d", &na[i] );    len = 0; memset ( first, 0, sizeof (first) );    st = 0; ed = n+1;    int sum = 0;    for ( i = 1; i <= n; i ++ ){        int x;        scanf ( "%d", &x );        if ( na[i] % 2 == 1 ) ins ( st, i, x );        else ins ( i, ed, x );        sum += x;    }    for ( i = 1; i < n; i ++ ){        for ( j = i+1; j <= n; j ++ ){            if ( check ( na[i], na[j] ) == true ){                if ( na[i] % 2 == 0 ) ins ( j, i, inf );                else ins ( i, j, inf );            }        }    }    int ans = 0, delta;    while ( bfs () ){        while ( delta = dfs ( st, inf ) ) ans += delta;    }    printf ( "%d\n", sum-ans );    return 0;}

记住,在进行平方操作时,请注意1Ai,Bi106,所以会爆int.. 我就因为这个错了两次啊..

论对拍的重要性啊..

0 0
原创粉丝点击