Description
Input第一行一个正整数N。
第二行共包括N个正整数,第 个正整数表示Ai。
第三行共包括N个正整数,第 个正整数表示Bi。
Output
共一行,包括一个正整数,表示在合法的选择条件下,可以获得的能量值总和的最大值。
Sample Input
4
3 4 5 12
9 8 30 9Sample Output
39
HINT
1<=N<=1000,1<=Ai,Bi<=10^6
这道题也是一道很好的题啊.. 值得去想一想
因为题目要求我们求最大值,那我们就想,能不能把它转化成总和减去损失的最小值呢?对了,就是最小割
首先我们先想一下一个割边的模型,也就是每个点连源连汇,然后割掉其中一条边表示选这个点进入集合所损失的价值,割掉另一条边表示不选这个点进入集合所损失的价值
又由于两个点是会因为某些条件不能在同一个集合中,所以我们要这样建边:
如下:
请注意,中间这一条边是单向边而不是各位认为的双向边
假如两个点都割【选】的边,那么肯定会存在有某个点割【不选】的边使得这种方案的最小割比当前的优,因为存在一条【不选】->【inf】->【不选】的增广路。但是,如果我现在割掉两个【不选】的边,并没有什么关系啊..
那么你也许会问,这个东西保证是二分图吗。那我下面给出证明咯
1.假如两个点都为偶数,那么他们满足第二个条件
2.加入两个点都为奇数,那么他们满足第一个条件
至于为什么,自己好好想想
所以就酱紫咯..
#include
#include
#include
#include
#include
#include
#define LL long long
using 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;
}
记住,在进行平方操作时,请注意 1≤Ai,Bi≤106 ,所以会爆int.. 我就因为这个错了两次啊..
论对拍的重要性啊..