题目链接:http://codeforces.com/problemset/problem/498/C
题意:给出N个数,再给出M对关系,每次操作可以从这M对中选出一对数同除它们的约数,问最多能进行多少次操作
思路:要操作次数多,那么对于每对数每次操作必定同除它们的素因子公约数,故而先对这N个数进行合数分解,然后再以分解出的质因子奇偶建图跑最大流
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <climits>
#include <functional>
#include <deque>
#include <ctime>
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long ll;
const int MAXN = 3000;
const int MAXM = 100010;
const int INF = 0x3f3f3f3f;
struct Edge
{
int to, next, cap, flow;
} edge[MAXM];
int tol;
int Head[MAXN];
int gap[MAXN], dep[MAXN], cur[MAXN];
void init()
{
tol = 0;
memset(Head, -1, sizeof(Head));
}
void addedge(int u, int v, int w, int rw = 0)
{
edge[tol].to = v;
edge[tol].cap = w;
edge[tol].flow = 0;
edge[tol].next = Head[u];
Head[u] = tol++;
edge[tol].to = u;
edge[tol].cap = rw;
edge[tol].flow = 0;
edge[tol].next = Head[v];
Head[v] = tol++;
}
int Q[MAXN];
void BFS(int start, int end)
{
memset(dep, -1, sizeof(dep));
memset(gap, 0, sizeof(gap));
gap[0] = 1;
int front = 0, rear = 0;
dep[end] = 0;
Q[rear++] = end;
while (front != rear)
{
int u = Q[front++];
for (int i = Head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if (dep[v] != -1)continue;
Q[rear++] = v;
dep[v] = dep[u] + 1;
gap[dep[v]]++;
}
}
}
int S[MAXN];
int sap(int start, int end, int N)
{
BFS(start, end);
memcpy(cur, Head, sizeof(Head));
int top = 0;
int u = start;
int ans = 0;
while (dep[start] < N)
{
if (u == end)
{
int Min = INF;
int inser;
for (int i = 0; i < top; i++)
if (Min > edge[S[i]].cap - edge[S[i]].flow)
{
Min = edge[S[i]].cap - edge[S[i]].flow;
inser = i;
}
for (int i = 0; i < top; i++)
{
edge[S[i]].flow += Min;
edge[S[i] ^ 1].flow -= Min;
}
ans += Min;
top = inser;
u = edge[S[top] ^ 1].to;
continue;
}
bool flag = false;
int v;
for (int i = cur[u]; i != -1; i = edge[i].next)
{
v = edge[i].to;
if (edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u])
{
flag = true;
cur[u] = i;
break;
}
}
if (flag)
{
S[top++] = cur[u];
u = v;
continue;
}
int Min = N;
for (int i = Head[u]; i != -1; i = edge[i].next)
if (edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)
{
Min = dep[edge[i].to];
cur[u] = i;
}
gap[dep[u]]--;
if (!gap[dep[u]])return ans;
dep[u] = Min + 1;
gap[dep[u]]++;
if (u != start)u = edge[S[--top] ^ 1].to;
}
return ans;
}
vector <pair<int, int> > v[MAXN];
int num[MAXN][MAXN];
void factor(int id, int x)
{
int tmp = x;
for (int i = 2; i <= sqrt(tmp); i++)
{
if (tmp % i == 0)
{
tmp /= i;
int sz = v[id].size();
if (!sz)
v[id].push_back(make_pair(i, 1));
else
{
if (v[id][sz - 1].first == i)
v[id][sz - 1].second++;
else
v[id].push_back(make_pair(i, 1));
}
i--;
}
if (tmp == 1) break;
}
if (tmp != 1) v[id].push_back(make_pair(tmp, 1));
if (v[id].size() == 0 && x != 1)
v[id].push_back(make_pair(x, 1));
}
int main()
{
int n, m;
while (~scanf("%d%d", &n, &m))
{
for (int i = 0; i < n; i++)
{
int x;
scanf("%d", &x);
factor(i, x);
}
init();
int cnt = 1;
for (int i = 0; i < n; i++)
for (int j = 0; j < v[i].size(); j++)
num[i][j] = cnt++;
int s = 0, t = cnt;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < v[i].size(); j++)
{
int id = num[i][j];
if (i % 2 == 1)
addedge(s, id, v[i][j].second);
else
addedge(id, t, v[i][j].second);
}
}
for (int i = 0; i < m; i++)
{
int x, y;
scanf("%d%d", &x, &y);
x--, y--;
if (x % 2 == 0) swap(x, y);
for (int j = 0; j < v[x].size(); j++)
{
int idx = num[x][j];
for (int k = 0; k < v[y].size(); k++)
{
int idy = num[y][k];
if (v[x][j].first == v[y][k].first)
addedge(idx, idy, INF);
}
}
}
cout << sap(s, t, t + 1) << endl;
}
return 0;
}