4514: [Sdoi2016]数字配对
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 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 long
typedef 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;
else
road[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;
}