特别神奇的一道题。。。
一开始想的是拆点,图好复杂、、、
上网查了查,原来两奇数之间不存在正整数c^2=a^2+b^2(哪位神犇能来证明一下)
于是建图就好想了,任意奇数之间不满足条件1,任意偶数之间不满足条件2
原点向奇数连边,容量就是这个数,偶数向汇点连边
任意两个不能同时选的数(一奇一偶),之间连一条容量为正无穷的边(这样不选哪个就会被割掉)
跑一遍最大流,用所有数之和减去最大流就是答案。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define maxn 10100
#define maxm 100100
#define inf 0x7fffffff
#define LL long long
using namespace std;
int n;
int u[maxm],v[maxm],w[maxm],st[maxn],next[maxm],other[maxm],d[maxn],num[maxn],last[maxn];
int len,tot,s,t,full,ans;
int a,s1[maxn][2],s2[maxn][2];
void addedge(int x,int y,int z)
{
len++;u[len]=x;v[len]=y;w[len]=z;next[len]=st[x];st[x]=len;other[len]=len+1;
len++;u[len]=y;v[len]=x;w[len]=0;next[len]=st[y];st[y]=len;other[len]=len-1;
}
int dfs(int now,int flow)
{
if (now==t) return flow;
int p=0,ans=0,j=last[now];
while (j)
{
if (d[v[j]]+1==d[u[j]] && w[j]>0) {
last[now]=j;
p=dfs(v[j],min(flow-ans,w[j]));
w[j]-=p;w[other[j]]+=p;
ans+=p;
if (ans==flow) return ans;
if (d[s]==tot) return ans;
}
j=next[j];
}
num[d[now]]--;if (num[d[now]]==0) d[s]=tot;
d[now]++;num[d[now]]++;
last[now]=st[now];
return ans;
}
int gcd(int a,int b) { return b?gcd(b,a%b):a; }
bool calc(LL a,LL b) { LL c=(LL)sqrt(a*a+b*b); return a*a+b*b==c*c; }
int main()
{
scanf("%d",&n);
s1[0][0]=0;s2[0][0]=0;
tot=2;s=1;t=2;full=0;
for (int i=1;i<=n;i++)
{
scanf("%d",&a);
full+=a;
if (a%2==1) { s1[0][0]++;s1[s1[0][0]][0]=a;tot++;s1[s1[0][0]][1]=tot;addedge(s,tot,a); }
else { s2[0][0]++;s2[s2[0][0]][0]=a;tot++;s2[s2[0][0]][1]=tot;addedge(tot,t,a); }
}
for (int i=1;i<=s1[0][0];i++)
for (int j=1;j<=s2[0][0];j++)
{
if (gcd(s1[i][0],s2[j][0])==1 && calc(s1[i][0],s2[j][0])) addedge(s1[i][1],s2[j][1],inf);
}
memset(d,0,sizeof(d));
memset(num,0,sizeof(num));
num[0]=tot;
for (int i=1;i<=tot;i++) last[i]=st[i];
while (d[s]<tot) ans+=dfs(s,inf);
printf("%d",full-ans);
return 0;
}
代码丑陋不喜勿喷。。。