码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj3275:最小割

时间:2016-01-12 21:28:52      阅读:263      评论:0      收藏:0      [点我收藏+]

标签:

看了师兄的建图方法,然后YY一下懂了一点?=>建图后即是求最小割,也就是说求最少去掉几条边就能使图不连通,图不连通意味着不会有两个相互矛盾的节点存在,若能联通的话会有两个相互矛盾的节点能够同时存在,所以=>("

S->每个奇数,每个偶数->T各连一条边, 容量为这个数字.然后不能同时选的两个数连容量为+oo的边. 总数-最大流即是答案.

因为满足a2+b2=c2的a,b一定是一奇一偶或者两个偶数, 2偶不满足gcd=1, 所以两个数不能同时选一定是一奇一偶.") 

以上引自sj师兄。两个奇数证明一下不难得出。

然后又是错了一个地方然后。。还有判断a*a+b*b=c*c不会判断,orz。

---------------------------------------------------------------------------------------

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define rep(i,n) for(int i=1;i<=n;i++)
#define clr(x,c) memset(x,c,sizeof(x))
#define ll long long
const int inf=0x3f3f3f3f;
int read(){
 int x=0,f=1;char c=getchar();
 while(!isdigit(c)){
  if(c==‘-‘) f=-1;
  c=getchar();
 }
 while(isdigit(c)){
  x=x*10+c-‘0‘;
  c=getchar();
 }
 return x*f;
}


struct edge{
 int to,cap;
 edge *next,*rev;
};
edge e[400000],*cur[3005],*head[3005],*p[3005],*pt;
int d[3005],cnt[3005],a[3005];
void add(int u,int v,int d){
 pt->to=v;
 pt->cap=d;
 pt->next=head[u];
 head[u]=pt++;
}
void adde(int u,int v,int d){
 add(u,v,d);add(v,u,0);
 head[u]->rev=head[v];
 head[v]->rev=head[u];
}


int gcd(int x,int y){
 return y?gcd(y,x%y):x;
}
bool pd(int x,int y){
 if(gcd(x,y)!=1) return false;
 ll tmp=(ll)x*x+(ll)y*y;
 ll t=sqrt(tmp);
 if(tmp==t*t) return true;
 return false;
}


int maxflow(int s,int t,int n){
 int flow=0,a=inf,x=s;
 clr(cnt,0);
 clr(d,0);cnt[0]=n;
 while(d[s]<n){
  edge *ee;
  for(ee=cur[x];ee;ee=ee->next){
   if(ee->cap>0&&d[ee->to]==d[x]-1)
     break;
  }
  if(ee){
   a=min(a,ee->cap);
   cur[x]=p[ee->to]=ee;
   x=ee->to;
   if(x==t){
    while(x!=s){
     p[x]->cap-=a;
     p[x]->rev->cap+=a;
     x=p[x]->rev->to;
    }
    flow+=a;
    a=inf;
   }
  }
  else{
   if(--cnt[d[x]]==0) break;  //又是这里又是这里
   d[x]=n;
   for(ee=head[x];ee;ee=ee->next){
    if(ee->cap>0&&d[ee->to]+1<d[x]){
     d[x]=d[ee->to]+1;
     cur[x]=ee;
    }
   }
   cnt[d[x]]++;
   if(x!=s) x=p[x]->rev->to;
  }
 }
 return flow;
}


int main(){
 int n=read(),s=0,t=n+1,tot=t+1,ans=0;
 pt=e;
 rep(i,n){
  a[i]=read();ans+=a[i];
  a[i]%2?adde(s,i,a[i]):adde(i,t,a[i]);
 }
 rep(i,n)
     if(a[i]%2)
        rep(j,n)
           if(a[j]%2==0&&pd(a[i],a[j]))
            adde(i,j,inf);
 printf("%d\n",ans-maxflow(s,t,tot));
 return 0;
}

---------------------------------------------------------------------------------------

 

3275: Number

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 561  Solved: 249
[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

 

 

[Submit][Status][Discuss]


HOME Back

bzoj3275:最小割

标签:

原文地址:http://www.cnblogs.com/fighting-to-the-end/p/5125437.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!