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

 

【思路】

       最小割。

       注意到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 }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值