bzoj 4514: [Sdoi2016]数字配对(二分图+费用最大流)

来源:互联网 发布:电脑怎么检查网络 编辑:程序博客网 时间:2024/06/07 18:23

4514: [Sdoi2016]数字配对

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1840  Solved: 703
[Submit][Status][Discuss]

Description

有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci。
若两个数字 ai、aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数,
那么这两个数字可以配对,并获得 ci×cj 的价值。
一个数字只能参与一次配对,可以不参与配对。
在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。

Input

第一行一个整数 n。
第二行 n 个整数 a1、a2、……、an。
第三行 n 个整数 b1、b2、……、bn。
第四行 n 个整数 c1、c2、……、cn。

Output

 一行一个数,最多进行多少次配对

Sample Input

3
2 4 8
2 200 7
-1 -2 1

Sample Output

4


如果a是b的倍数,且a/b是质数:

①a能分解为奇数个质数相乘,那么a到b+n连一条容量为inf,费用为c[a]*c[b]的边

②a能分解为偶数个质数相乘,那么b到a+n连一条容量为inf,费用为c[a]*c[b]的边

如果a能分解为奇数个质数相乘,那么源点到a连一条容量为sum[a],费用为0的边

如果a能分解为偶数个质数相乘,那么a到汇点连一条容量为sum[a],费用为0的边

这个网络去掉源点汇点及其边后就是一张二分图

之后求出在费用不低于0的情况下的最大流就是答案

改下SPFA

#include<stdio.h>#include<string.h>#include<math.h>#include<stdlib.h>#include<algorithm>#include<queue>using namespace std;#define LL long longtypedef struct{int x;int y, z;int tp;}Res;Res s[205];typedef struct{int flow;LL cost;}Edge;Edge road[505][505];int dis, T, link[505], vis[505];LL best[505];int Spfa();int Jud(int x){int i;if(x<=1)return 0;for(i=2;i*i<=x;i++){if(x%i==0)return 0;}return 1;}int Sech(int x){int i, sum = 0;for(i=2;i*i<=x;i++){while(x%i==0){sum++;x /= i;}}if(x!=1)sum++;return 2-(sum%2);}int main(void){LL ans, sum;int n, x, i, j, pre, flow;while(scanf("%d", &n)!=EOF){for(i=1;i<=n;i++){scanf("%d", &s[i].x);s[i].tp = Sech(s[i].x);}for(i=1;i<=n;i++)scanf("%d", &s[i].y);for(i=1;i<=n;i++)scanf("%d", &s[i].z);T = 2*n+1;for(i=1;i<=n;i++){if(s[i].tp==1)road[0][i].flow = s[i].y;elseroad[n+i][T].flow = s[i].y;}for(i=1;i<=n;i++){for(j=1;j<=n;j++){if(s[i].x%s[j].x==0 && Jud(s[i].x/s[j].x)){if(s[i].tp==1){road[i][n+j].flow = 2147483647;road[i][n+j].cost = (LL)s[i].z*s[j].z;road[n+j][i].cost = -(LL)s[i].z*s[j].z;}else{road[j][n+i].flow = 2147483647;road[j][n+i].cost = (LL)s[i].z*s[j].z;road[n+i][j].cost = -(LL)s[i].z*s[j].z;}}}}ans = flow = 0;while(Spfa()){x = T;dis = 100000000;while(x!=0){pre = link[x];dis = min(dis, road[pre][x].flow);x = pre;}x = T;sum = 0;while(x!=0){pre = link[x];road[pre][x].flow -= dis;road[x][pre].flow += dis;sum += road[pre][x].cost;x = pre;}if(ans+sum*dis<0){flow += -ans/sum;break;}ans += sum*dis;flow += dis;}printf("%d\n", flow);}return 0;}int Spfa(){int i, now;memset(link, -1, sizeof(link));memset(vis, 0, sizeof(vis));memset(best, -62, sizeof(best));best[0] = 0;queue<int> q;q.push(0);while(q.empty()==0){now = q.front();q.pop();for(i=1;i<=T;i++){if(road[now][i].flow>0 && best[i]<best[now]+road[now][i].cost){best[i] = best[now]+road[now][i].cost;link[i] = now;if(vis[i]==0){vis[i] = 1;q.push(i);}}}vis[now] = 0;}if(best[T]>=-1e17)return 1;return 0;}


原创粉丝点击