bzoj3158&3275: 千钧一发(最小割)
3158: 千钧一发
题目:传送门
题解:
这是一道很好的题啊...极力推荐
细看题目:要求一个最大价值,那么我们可以转换成求损失的价值最小
那很明显就是最小割的经典题目啊?!
但是这里两个子集的分化并不明显...GG
耐心一点,从题目的要求再入手:
对于第二个要求,如果两点的a值都为偶数,那么肯定满足
那如果两个数都为奇数的话,也必定满足要求一,证明如下:
1、一个奇数的平方%4为1,一个偶数的平方%4为0
2、两个奇数的平方和%4为2
3、如果两个奇数的平方和是一个奇数的平方,那么%4应该为1,不符合
4、如果两个奇数的平方和是一个偶数的平方,那么%4应该为0,不符合
因此得证。
这样子思考的话,两个子集的分化就较为明显了:
st向a值为奇数的相连,a值为偶数的向ed相连,容量都为b值;这样子所形成的两个子集里面的点一定都是符合要求的。
最后一步,也是最关键的一步:
两个子集之间两两匹配,如果当前匹配的两个点是不符合要求的,就将这两个点相连,容量为无限大。
有什么用呢?自己画几个图便很容易理解:
这时候我们跑最小割的话,割出来的边就是损失价值的最小值
用sum-最小割就是答案啊
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #define qread(x) x=read() 7 using namespace std; 8 typedef long long LL; 9 const LL inf=999999999; 10 LL n,st,ed,sum; 11 LL A[1100],B[1100]; 12 inline LL read() 13 { 14 LL f=1,x=0;char ch; 15 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 16 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 17 return f*x; 18 } 19 struct node 20 { 21 LL x,y,c,next,other; 22 }a[2100000];LL len,last[110000]; 23 void ins(LL x,LL y,LL c) 24 { 25 int k1,k2; 26 k1=++len; 27 a[len].x=x;a[len].y=y;a[len].c=c; 28 a[len].next=last[x];last[x]=len; 29 30 k2=++len; 31 a[len].x=y;a[len].y=x;a[len].c=0; 32 a[len].next=last[y];last[y]=len; 33 34 a[k1].other=k2; 35 a[k2].other=k1; 36 } 37 LL list[11000],h[11000],head,tail; 38 bool bt_h() 39 { 40 memset(h,0,sizeof(h));h[st]=1; 41 list[1]=st;head=1;tail=2; 42 while(head!=tail) 43 { 44 int x=list[head]; 45 for(int k=last[x];k;k=a[k].next) 46 { 47 int y=a[k].y; 48 if(h[y]==0 && a[k].c) 49 { 50 h[y]=h[x]+1; 51 list[tail++]=y; 52 } 53 } 54 head++; 55 } 56 if(h[ed])return true; 57 return false; 58 } 59 LL find_flow(LL x,LL flow) 60 { 61 if(x==ed)return flow; 62 LL s=0,t; 63 for(int k=last[x];k;k=a[k].next) 64 { 65 int y=a[k].y; 66 if(h[y]==h[x]+1 && a[k].c>0 && flow>s) 67 { 68 s+=t=find_flow(y,min(a[k].c,flow-s)); 69 a[k].c-=t;a[a[k].other].c+=t; 70 } 71 } 72 if(s==0)h[x]=0; 73 return s; 74 } 75 LL gcd(LL a,LL b) 76 { 77 return a==0?b:gcd(b%a,a); 78 } 79 bool pd(LL x,LL y) 80 { 81 LL T=x*x+y*y,t=sqrt(T); 82 if(t*t!=T)return true; 83 if(gcd(x,y)>1)return true; 84 return false; 85 } 86 int main() 87 { 88 sum=0; 89 qread(n); 90 len=0;memset(last,0,sizeof(last)); 91 for(int i=1;i<=n;i++)qread(A[i]); 92 for(int i=1;i<=n;i++){qread(B[i]);sum+=B[i];} 93 st=n+1;ed=st+1; 94 for(int i=1;i<=n;i++) 95 { 96 if(A[i]%2==1)ins(st,i,B[i]); 97 else ins(i,ed,B[i]); 98 } 99 for(int i=1;i<=n;i++) 100 for(int j=1;j<=n;j++) 101 if((A[i]%2==1) && (A[j]%2==0) && !pd(A[i],A[j])) 102 ins(i,j,inf); 103 LL ans=0; 104 while(bt_h())ans+=find_flow(st,inf); 105 printf("%lld\n",sum-ans); 106 return 0; 107 }