BZOJ3275 Number (最小割)

本文探讨了一种解决特定数学问题的算法实现过程。通过构建图并利用最大流算法,作者解决了奇偶数配对问题,从而计算出最优解。代码展示了从问题定义到算法实现的全过程,包括图构建、最大流计算以及最终答案输出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

特别神奇的一道题。。。

一开始想的是拆点,图好复杂、、、

上网查了查,原来两奇数之间不存在正整数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;
}


代码丑陋不喜勿喷。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值