BZOJ 3158: 千钧一发
题目
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 }