【bzoj 3275】Number(最小割)
来源:互联网 发布:国际条约集数据库 编辑:程序博客网 时间:2024/04/29 05:35
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 718 Solved: 305
[Submit][Status][Discuss]
Description
有N个正整数,需要从中选出一些数,使这些数的和最大。
若两个数a,b同时满足以下条件,则a,b不能同时被选
1:存在正整数C,使a*a+b*b=c*c
2:gcd(a,b)=1
Input
第一行一个正整数n,表示数的个数。
第二行n个正整数a1,a2,?an。
Output
最大的和。
Sample Input
5
3 4 5 6 7
Sample Output
22
HINT
n<=3000。
Source
网络流
【题解 :网络流最小割。】
[原本的思路是将每个点与源点连边、与汇点连边,流量分别为当前数,然后预处理出所有不能共存的数对,并在它们之间连一条流量为INF的边,赶脚十分的科学。然而发现会MLE。。。表示不开森]
【**后来想到刚做完的圈地,黑白染色(黑:奇数,白:偶数),源点与黑点连流量为当前数的边,白点与汇点连流量为当前数的边,把不能共存的数对连一条流量为INF的边。 然后跑最大流(=最小割)】
【从网上得知:可以证明奇数和奇数(不能构成勾股数)、偶数和偶数(最大公因数一定不会是1)是一定可以共存的,所以有可能连边的只可能是奇数和偶数之间所以只要枚举判断每两个奇数和偶数之间能否连边即可(奇数向偶数连边啊,我刚开始忘判断哪个是奇数哪个是偶数,WA成一坨啊 233)**】
【代码】
#include<cmath>#include<queue>#include<cstdio>#include<cstring>#include<algorithm>#define INF 0x7fffffffusing namespace std;int a[1200010],next[1200010],p[3010],remain[1200010],tot;int dis[3010],cur[3010];int ls[3010],rs[3010],ll,rr;int c[3010],n,S,T,sum,s,mincut;int gcd(int a,int b){ if (!(a%b)) return b; else return gcd(b,a%b);}inline void add(int x,int y,int flow){ tot++; a[tot]=y; next[tot]=p[x]; p[x]=tot; remain[tot]=flow; tot++; a[tot]=x; next[tot]=p[y]; p[y]=tot; remain[tot]=0;}inline bool bfs(int s,int t){ queue<int>que; memset(dis,-1,sizeof(dis)); for(int i=s;i<=t;++i) cur[i]=p[i]; dis[s]=0; que.push(s); while(!que.empty()) { int u,v; u=que.front(); que.pop(); v=p[u]; while(v!=-1) { if (remain[v]&&dis[a[v]]<0) { dis[a[v]]=dis[u]+1; que.push(a[v]); } v=next[v]; } } if(dis[t]<0) return false; else return true;}inline int dfs(int now,int t,int flow){ if (!flow||now==t) return flow; int u=cur[now],s1=0,s; while(u!=-1) { cur[now]=u; if (dis[a[u]]==dis[now]+1&&(s=dfs(a[u],t,min(flow,remain[u])))) { s1+=s; flow-=s; remain[u]-=s; remain[u^1]+=s; if (!flow) break; } u=next[u]; } return s1;}int main(){ int i,j; memset(next,-1,sizeof(next)); memset(p,-1,sizeof(p)); scanf("%d",&n); T=n+1; tot=-1; for (i=1;i<=n;++i) { scanf("%d",&c[i]); if (c[i]&1) add(S,i,c[i]),ls[++ll]=i; else add(i,T,c[i]),rs[++rr]=i; sum+=c[i]; } for (i=1;i<=ll;++i) for (j=1;j<=rr;++j) { long long k=c[ls[i]]*c[ls[i]]+c[rs[j]]*c[rs[j]]; long long t=sqrt(k); if (t*t==k&&gcd(c[ls[i]],c[rs[j]])==1) add(ls[i],rs[j],INF); } while(bfs(S,T)) while(s=dfs(S,T,0x7fffffff)) mincut+=s; sum-=mincut; printf("%d\n",sum); return 0;}
0 0
- 【bzoj 3275】Number(最小割)
- BZOJ 3275 Number 最小割
- bzoj 3275: Number 最小割
- BZOJ 3275: Number 最小割
- BZOJ 3275 Number && 3158 千钧一发 最小割
- bzoj 3275(最小割)
- 3275: Number 最小割
- 【BZOJ】【P3275】【Number】【题解】【最小割】
- bzoj 2127(最小割)
- bzoj 3144(最小割)
- bzoj 3894(最小割)
- bzoj 2132(最小割)
- bzoj 1458(最小割)
- BZOJ3275 Number (最小割)
- [BZOJ3275]Number(最小割)
- bzoj 2229: [Zjoi2011]最小割 分治最小割(最小割树)
- BZOJ 2127: happiness(最小割)
- bzoj 3158 千钧一发(最小割)
- Android开发中的MVP架构详解
- 【数据结构】Singly-Linked-List 单链表(更新时间:2016-04-07)
- Java异常处理机制 try-catch-finally
- 函数
- Maven入门 第一章
- 【bzoj 3275】Number(最小割)
- 3D幻灯片
- 最小生成树
- [LeetCode]208. Implement Trie (Prefix Tree)
- 1004. 成绩排名 (20)
- android基础部分再学习---Context
- LintCode_150_买卖股票的最佳时机 II
- Insert Interval
- DOCTYPE声明作用及用法详解