bzoj3275 Number

Number

Time Limit: 10 Sec Memory Limit: 128 MB

Description

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

Input

第一行一个正整数(n),表示数的个数。(n<=3000)
第二行(n)个正整数(a_1,a_2,...a_n)

Output

最大的和

Sample Input

5
3 4 5 6 7

Sample Output

22

今天下午本来仔细的再学一下数学和其他相关知识的。。。。发现很多题都或多或少有点问题。。。。尴尬癌犯了啊~~~
写一道网络流的题吧。
表示我记得千钧一发。。。。一模一样有木有。。。
复习一下网络流吧(就算省选考到我也不一定会建图啊233)


#include<bits/stdc++.h>
using namespace std;
const int s = 0, t = 3010, maxn = 4001, INF = 0x3f3f3f3f;
struct lpl{
	int to, dis;
}lin;
int even[maxn], odd[maxn], layer[maxn];
int n, x, cnt = -1, tot_1, tot_2;
long long ans;
vector<lpl> edge;
vector<int> point[maxn]; 
queue<int> q;

inline void putit()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i){
		scanf("%d", &x); ans += x;
		if(x & 1) odd[++tot_1] = x;
		else even[++tot_2] = x;
	}
}

inline void connect(int a, int b, int w)
{
	cnt++; lin.to = b; lin.dis = w; point[a].push_back(cnt); edge.push_back(lin);
	cnt++; lin.to = a; lin.dis = 0; point[b].push_back(cnt); edge.push_back(lin);
}

inline void prepare()
{
	for(int i = 1; i <= tot_1; ++i) connect(s, i, odd[i]);
	for(int i = 1; i <= tot_2; ++i) connect(i + tot_1, t, even[i]);
}

inline int gcd(int a, int b)
{
	if(a < b) swap(a, b);
	return (a % b == 0) ? b : gcd(b, a % b);
}

inline bool check(int a, int b)
{
	if(gcd(a, b) != 1) return false;
	long long c = sqrt((long long)a * a + b * b);
	if(c * c == ((long long)a * a + b * b)) return true;
	return false;
}

inline void workk()
{
	for(int i = 1; i <= tot_1; ++i)
		for(int j = 1; j <= tot_2; ++j)
			if(check(odd[i], even[j])) connect(i, j + tot_1, INF);
}

inline bool bfs()
{
	memset(layer, 0, sizeof(layer));
	layer[s] = 1; q.push(s);
	while(!q.empty()){
		int now = q.front(); q.pop();
		for(int i = point[now].size() - 1; i >= 0; --i){
			lin = edge[point[now][i]];
			if(layer[lin.to] || !lin.dis) continue;
			layer[lin.to] = layer[now] + 1; q.push(lin.to);
		}
	}
	return layer[t];
}

long long dfs(int a, int w)
{
	if(a == t || w == 0) return w;
	long long ret = 0;
	for(int i = point[a].size() - 1; i >= 0; --i){
		int now = point[a][i];
		if(layer[edge[now].to] != layer[a] + 1 || edge[now].dis <= 0) continue;
		long long tmp = dfs(edge[now].to, min(edge[now].dis, w));
		edge[now].dis -= tmp; edge[now ^ 1].dis += tmp; w -= tmp; ret += tmp;
		if(!w) break;
	}
	return ret;
}

inline long long Dinic()
{
	long long ret = 0;
	while(bfs()) ret += dfs(s, INF);
	return ret;
}

int main()
{
	putit();
	prepare();
	workk();
	cout << ans - Dinic();
	return 0;
}

心如花木,向阳而生。
原文地址:https://www.cnblogs.com/LLppdd/p/8717863.html