BZOJ 3158: 千钧一发

题目

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 388  Solved: 152
[Submit][Status]

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

题解

这道题目是最小割建图,但是套普通的模型会发现要建出负边来了。所以我们必须反向某些边的定义。由题目我们发现,所有的偶数两两之间一定符合第二条规则,而所有的奇数两两之间一定符合第一条规则,那么二关关系只会建立在奇数和偶数之间了。我们可以考虑反向所有偶数边的定义,在源点到偶数特征值的点之间连一条为当前边价值的边,在奇数特征值和汇点之间连一条为当前边价值的边。然后考虑所有奇数点,从所有奇数点连一条流量为INF的边到和他冲突的偶数点,跑一边最大流就好了!然后用全部的价值和减去最大流结果就是答案。

代码

  1 /*Author:WNJXYK*/
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<iostream>
  6 #include<queue>
  7 using namespace std;
  8 
  9 
 10 inline int remin(int a,int b){return a<b?a:b;}
 11 inline long long sqr(int x){return (long long)x*(long long)x;}
 12 
 13 const int Maxn=1500;
 14 const int Maxm=Maxn*Maxn;
 15 const int inf=2100000000;
 16 struct Edge{
 17     int u,v,f,nxt;
 18     Edge(){}
 19     Edge(int a,int b,int c,int d){
 20         u=a;
 21         v=b;
 22         f=c;
 23         nxt=d;
 24     }
 25 }; 
 26 Edge e[Maxm+10];
 27 int g[Maxn+10];
 28 int cnt=1;
 29 int sink,src;
 30 inline void insertEdge(int u,int v,int f){
 31     cnt++;
 32     e[cnt]=Edge(u,v,f,g[u]);
 33     g[u]=cnt;
 34 }
 35 inline void addEdge(int u,int v,int f){
 36     insertEdge(u,v,f);
 37     insertEdge(v,u,0);
 38 }
 39 
 40 queue<int> que;
 41 int dist[Maxn+10];
 42 
 43 bool spfa(){
 44     while(!que.empty()) que.pop();
 45     memset(dist,-1,sizeof(dist));
 46     dist[src]=0;
 47     que.push(src);
 48     while(!que.empty()){
 49         int now=que.front();
 50         que.pop();
 51         for (int i=g[now];i;i=e[i].nxt){
 52             if (e[i].f!=0 && dist[e[i].v]==-1){
 53                 dist[e[i].v]=dist[now]+1;
 54                 que.push(e[i].v);
 55             }
 56         }
 57     }
 58     return dist[sink]!=-1;
 59 }
 60 
 61 int dfs(int x,int delta){
 62     int ret=0;
 63     if (x==sink){
 64         return delta;
 65     }else{
 66         for (int i=g[x];i;i=e[i].nxt){
 67             if (e[i].f!=0 && dist[e[i].v]==dist[x]+1){
 68                 int ddelta=dfs(e[i].v,remin(e[i].f,delta));
 69                 e[i].f-=ddelta; 
 70                 e[i^1].f+=ddelta; 
 71                 ret+=ddelta; 
 72                 delta-=ddelta;
 73             }
 74         }
 75     }
 76     return ret;
 77 }
 78 
 79 int dinic(){
 80     int ret=0;
 81     while(spfa()){
 82         ret+=dfs(src,inf);
 83     }
 84     return ret;
 85 }
 86 
 87 int n;
 88 int a[1010];
 89 int b[1010];
 90 
 91 inline int gcd(int x,int y)
 92 {
 93      int m=x%y;
 94      while(m!=0)
 95      {
 96           x=y;
 97           y=m;
 98           m=x%y;
 99      }
100      return y;
101 } 
102 
103 int main(){
104     //freopen("3158.in","r",stdin);
105     //freopen("3158.out","w",stdout); 
106     scanf("%d",&n);
107     src=0;
108     sink=n+1;
109     for (int i=1;i<=n;i++)scanf("%d",&a[i]);
110     for (int i=1;i<=n;i++)scanf("%d",&b[i]);
111     long long sum=0;
112     for (int i=1;i<=n;i++){
113         if (a[i]%2==0){
114             addEdge(src,i,b[i]);
115         }else{
116             addEdge(i,sink,b[i]);
117         }
118         sum+=b[i];
119     }
120     for (int i=1;i<=n;i++){
121         if (a[i]%2==1) continue;
122         for (int j=1;j<=n;j++){
123             if (i==j) continue;
124             if ((a[i]+a[j])%2==0) continue;
125             if (gcd(a[i],a[j])!=1) continue;
126             long long tmp=sqr(a[i])+sqr(a[j]);
127             int tmpk=(int)floor(sqrt(tmp));
128             if (sqr(tmpk)!=tmp) continue;
129             addEdge(i,j,inf);
130         }
131     }
132     //printf("%llld\n",sum);
133     printf("%lld\n",sum-dinic());
134     return 0;
135 }
View Code

 

 

posted @ 2014-11-04 12:43  WNJXYK  阅读(202)  评论(0编辑  收藏  举报

WNJXYK-我今年一定要努力!