bzoj 3158 千钧一发(最小割)

3158: 千钧一发

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 767  Solved: 290
[Submit][Status][Discuss]

Description

Input

第一行一个正整数N。

第二行共包括N个正整数,第 个正整数表示Ai。

第三行共包括N个正整数,第 个正整数表示Bi。

Output

共一行,包括一个正整数,表示在合法的选择条件下,可以获得的能量值总和的最大值。

Sample Input

4
3 4 5 12
9 8 30 9

Sample Output

39

HINT

1<=N<=1000,1<=Ai,Bi<=10^6

Source

Katharon+#1

【思路】

最小割。

注意到ai,aj同时是偶数或同时是奇数时必定可以被同时选出:

1 同为偶数满足条件2

2 同为奇数时有(2a+1)^2+(2b+1)^2=2(2a^2+2b^2+2a+2b+1),所以满足条件1。

以此构二分图,设奇数为X结点偶数为Y结点,如果不满足任一条件则连边(Xi,Yj,INF),同时相应连S到X,Y到T的边容量为b,那么答案就是一个二分图最小割,即通过删除一些结点使得满足剩下的结点不相邻且有b之和最小。

【代码】

  1 #include<cstdio>
  2 #include<cmath>
  3 #include<queue>
  4 #include<cstring>
  5 #include<iostream>
  6 using namespace std;
  7
  8 typedef long long LL;
  9 const int maxn = 4000+10;
 10 const int INF = 1e9+1e9;
 11
 12 struct Edge{  int u,v,cap,flow;
 13 };
 14
 15 struct Dinic {
 16     int n,m,s,t;
 17     int d[maxn],cur[maxn],vis[maxn];
 18     vector<int> G[maxn];
 19     vector<Edge> es;
 20
 21     void init(int n) {
 22         this->n=n;
 23         for(int i=0;i<n;i++) G[i].clear();
 24         es.clear();
 25     }
 26     void AddEdge(int u,int v,int cap) {
 27         es.push_back((Edge){u,v,cap,0});
 28         es.push_back((Edge){v,u,0,0});
 29         m=es.size();
 30         G[u].push_back(m-2);
 31         G[v].push_back(m-1);
 32     }
 33     bool bfs() {
 34         queue<int> q;
 35         memset(vis,0,sizeof(vis));
 36         vis[s]=1; d[s]=0; q.push(s);
 37         while(!q.empty())    {
 38             int u=q.front(); q.pop();
 39             for(int i=0;i<G[u].size();i++) {
 40                 Edge &e=es[G[u][i]];
 41                 int v=e.v;
 42                 if(!vis[v] && e.cap>e.flow) {
 43                     vis[v]=1;
 44                     d[v]=d[u]+1;
 45                     q.push(v);
 46                 }
 47             }
 48         }
 49         return vis[t];
 50     }
 51     int dfs(int u,int a) {
 52         if(u==t || a==0) return a;
 53         int f,flow=0;
 54         for(int& i=cur[u];i<G[u].size();i++) {
 55             Edge& e=es[G[u][i]];
 56             int v=e.v;
 57             if(d[v]==d[u]+1 && (f=dfs(v,min(a,e.cap-e.flow)))>0) {
 58                 e.flow+=f;
 59                 es[G[u][i]^1].flow-=f;
 60                 flow+=f , a-=f;
 61                 if(!a) break;
 62             }
 63         }
 64         return flow;
 65     }
 66     int maxflow(int s,int t) {
 67         this->s=s , this->t=t;
 68         int flow=0;
 69         while(bfs()) {
 70             memset(cur,0,sizeof(cur));
 71             flow+=dfs(s,INF);
 72         }
 73         return flow;
 74     }
 75 } dc;
 76
 77 int n;
 78 int a[maxn],b[maxn];
 79
 80 bool issqr(LL x) { return sqrt(x)*sqrt(x) == x;
 81 }
 82 int gcd(int x,int y) {
 83     return y==0? x:gcd(y,x%y);
 84 }
 85 bool jud(LL x,LL y) {
 86     LL t=x*x+y*y , sq=sqrt(t);
 87     if(sq*sq!=t) return 1;
 88     if(gcd(x,y)>1) return 1;
 89     return 0;
 90 }
 91
 92 int main() {
 93     scanf("%d",&n);
 94     dc.init(n+2);
 95     int s=n,t=s+1;
 96     int ans=0;
 97     for(int i=0;i<n;i++) scanf("%d",&a[i]);
 98     for(int i=0;i<n;i++) scanf("%d",&b[i]) , ans+=b[i];
 99     for(int i=0;i<n;i++)
100         if((a[i]&1)) dc.AddEdge(s,i,b[i]);
101         else dc.AddEdge(i,t,b[i]);
102     for(int i=0;i<n;i++)  for(int j=0;j<n;j++)
103         if((a[i]&1) && (a[j]&1)==0)
104             if(!jud(a[i],a[j]))  dc.AddEdge(i,j,INF);
105     ans-=dc.maxflow(s,t);
106     printf("%d",ans);
107     return 0;
108 }
时间: 2024-10-12 04:12:51

bzoj 3158 千钧一发(最小割)的相关文章

BZOJ 3275 Number &amp;&amp; 3158 千钧一发 最小割

题目大意:给出一些数字,要求选出一些数字并保证所有数字和最大,要求这其中的数字任意两个至少满足一个条件,则不能同时被选:1.这两个数的平方和是完全平方数.2.gcd(a,b) = 1. 思路:我们可以将奇数和偶数分开来讨论,奇数不满足1,偶数不满足2,所以奇数和奇数,偶数和偶数不会互相影响.之后O(n^2)的讨论其他数字对,有影响就连边,流量正无穷,最后跑最小割最最大获利. CODE: #define _CRT_SECURE_NO_WARNINGS #include <cmath> #incl

【BZOJ-3275&amp;3158】Number&amp;千钧一发 最小割

3275: Number Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 748  Solved: 316[Submit][Status][Discuss] Description 有N个正整数,需要从中选出一些数,使这些数的和最大.若两个数a,b同时满足以下条件,则a,b不能同时被选1:存在正整数C,使a*a+b*b=c*c2:gcd(a,b)=1 Input 第一行一个正整数n,表示数的个数. 第二行n个正整数a1,a2,?an. Output

BZOJ 2561: 最小生成树(最小割)

U,V能在最小(大)生成树上,当且仅当权值比它小(大)的边无法连通U,V. 两次最小割就OK了. --------------------------------------------------------------------- #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> #include<que

BZOJ 2127: happiness( 最小割 )

最小割.. S连每个人(容量:选择理科的愉悦):每个人连T(容量:选择理科的愉悦) . 对于每一组(x, y, w)x和y同选理增加的愉悦w,新建节点V,V连x(INF),V连y(INF), S连V(w) 对于每一组(x, y, w)x和y同选文增加的愉悦w,新建节点V,x连V(INF),y连V(INF), V连T(w) ------------------------------------------------------------------- #include<cstdio> #i

【bzoj3158】千钧一发 最小割

题目描述 输入 第一行一个正整数N. 第二行共包括N个正整数,第 个正整数表示Ai. 第三行共包括N个正整数,第 个正整数表示Bi. 输出 共一行,包括一个正整数,表示在合法的选择条件下,可以获得的能量值总和的最大值. 样例输入 4 3 4 5 12 9 8 30 9 样例输出 39 题解 最小割 两个奇数一定满足条件1,两个偶数一定满足条件2,所以不满足条件的一定只存在于奇数和偶数之间. 因此S向奇数连边,偶数向T连边,不满足条件的奇数和偶数之间连边. 然后求最小割,答案为sum-mincut

BZOJ 2229 ZJOI2011 最小割 最小割+分治 400AC达成&amp;&amp;2000Submission达成

题目大意:给定一个图,多次询问有多少个点对之间的最小割小于等于某个值 最小割分治- - 首先朴素的想法是做O(n^2)遍网络流 但是这样显然是过不去的 根据一些结论,最小割最多有n-1个,这n-1个最小割构成一个最小割树 别问我为什么- - 因此我们分治寻找这n-1个最小割 每层分治,先任选两个点作为源汇做一遍最小割 然后找出S集和T集,对所有S集的点和T集的点构成的点对用本次得到的最小割更新一遍 注意更新的是全部S集和全部T集,不只是本次分治内部的S集和T集 然后将本次分治的点分成S集和T集,

[BZOJ 1797][AHOI2009]最小割(最小割关键边的判断)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1797 分析: 在残余网络中看: 对于第1问: 1.首先这个边必须是满流 2.其次这个边连接的两个点U,V必须属于两个SCC,即这个边必须为一个割 对于第2问: 在第1问的基础上,还要判断U和S.V和T是否分别在同一个SCC中,如果成立,那么这样才是必须的.

BZOJ 2521 最小生成树(最小割)

http://www.lydsy.com/JudgeOnline/problem.php?id=2521 题意:每次能增加一条边的权值1,求最小代价让一条边保证在最小生成树里 思路:如果两个点中有环,那么这条边必须不能是环的最大边,这样子把之前所有的边权值变成V+1-v[i],无向图网络流就可以了 1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5

bzoj 3144 切糕 —— 最小割

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3144 每个点拆成 R 个,连成一条链,边上是权值,割掉代表选这一层: 然后每个点的第 t 层向四周的点的第 t-d 层连边,就能达到选了第 i 条边,则四周的点必须选 i-d ~ T 范围的边,而对方反过来一连,就限制在 i-d ~ i+d 了: 竟然因为忘记 ct=1 而调了一小时呵呵... 代码如下: #include<cstdio> #include<cstring>