Description
在很久很久以前,曾经有两个国家和睦相处,无忧无虑的生活着。一年一度的评比大会开始了,作为和平的两国,一个朋友圈数量最多的永远都是最值得他人的尊敬,所以现在就是需要你求朋友圈的最大数目。
两个国家看成是AB两国,现在是两个国家的描述:
1. A国:每个人都有一个友善值,当两个A国人的友善值a、b,如果a xor b mod 2=1,
那么这两个人都是朋友,否则不是;
2. B国:每个人都有一个友善值,当两个B国人的友善值a、b,如果a xor b mod 2=0
或者 (a or b)化成二进制有奇数个1,那么两个人是朋友,否则不是朋友;
3. A、B两国之间的人也有可能是朋友,数据中将会给出A、B之间“朋友”的情况。
- 在AB两国,朋友圈的定义:一个朋友圈集合S,满足
S∈A∪ B ,对于所有的i,j∈ S ,i 和 j 是朋友
由于落后的古代,没有电脑这个也就成了每年最大的难题,而你能帮他们求出最大朋 友圈的人数吗?
Input
第一行t<=6,表示输入数据总数。
接下来t个数据:
第一行输入三个整数A,B,M,表示A国人数、B国人数、AB两国之间是朋友的对数;第二行A个数ai,表示A国第i个人的友善值;第三行B个数bi,表示B国第j个人的友善值;
第4——3+M行,每行两个整数(i,j),表示第i个A国人和第j个B国人是朋友。
Output
输出t行,每行,输出一个整数,表示最大朋友圈的数目。
Sample Input
2 4 7
1 2
2 6 5 4
1 1
1 2
1 3
2 1
2 2
2 3
2 4
Sample Output
5
【样例说明】
最大朋友圈包含A国第1、2人和B国第1、2、3人。
分析
可以从题目得到一些有用的信息:A国中最多只能选两个人;B国的人被分成两部分,每部分都是完全图,两部分之间有一些连边;要求一个最大的团。 。
显然一个图的最大团等于其反图的最大独立集,那么我们就把B国的反图建立出来,显然这是一个二分图。然后我们枚举在A中选择哪一个或两个人,再在B中跑最大独立集即可。
我在写的时候好多地方写错,比如说next写成to啊,i写成j啊,还有数组开小啊,各种神奇的问题。。。简直了!
代码
#include <bits/stdc++.h>
#define N 3005
#define ll long long
#define INF 0x7fffff
int s,t,ans;
struct NOTE
{
int to,next,c;
}e[N*N];
int head[N],cur[N];
int cnt;
void add(int x,int y,int c)
{
e[++cnt].to = y;
e[cnt].next = head[x];
e[cnt].c = c;
head[x] = cnt;
e[++cnt].to = x;
e[cnt].next = head[y];
e[cnt].c = 0;
head[y] = cnt;
}
int next[N];
int cntn;
void addedge(int x,int y)
{
e[++cnt].to = y;
e[cnt].next = next[x];
next[x] = cnt;
cnt++;
}
int dis[N];
int use[N];
bool bfs()
{
for (int i = s; i <= t; i++)
dis[i] = 0;
dis[s] = 1;
std::queue<int> Q;
Q.push(s);
while (!Q.empty())
{
int u = Q.front();
Q.pop();
for (int i = head[u]; i; i = e[i].next)
{
int now = e[i].to;
if (e[i].c && use[now] && !dis[now])
{
dis[now] = dis[u] + 1;
if (now == t)
return 1;
Q.push(now);
}
}
}
return 0;
}
int dfs(int x,int maxf)
{
if (!maxf || x == t)
return maxf;
int ret = 0;
for (int &i = cur[x]; i; i = e[i].next)
{
int now = e[i].to;
if (use[now] && e[i].c && dis[now] == dis[x] + 1)
{
int f = dfs(now,std::min(e[i].c,maxf - ret));
ret += f;
e[i].c -= f;
e[i ^ 1].c += f;
if (ret == maxf)
break;
}
}
return ret;
}
void dinic()
{
while (bfs())
{
for (int i = s; i <= t; i++)
cur[i] = head[i];
ans += dfs(s,INF);
}
}
void clear()
{
for (int i = cntn; i <= cnt; i+=2)
{
e[i].c = 1;
e[i ^ 1].c = 0;
}
}
int count(int x)
{
int tot = 0;
while (x)
{
tot++;
x -= x & (-x);
}
return tot;
}
int A,B,m;
int a[N],b[N];
int main()
{
scanf("%d%d%d",&A,&B,&m);
for (int i = 1; i <= A; i++)
{
scanf("%d",&a[i]);
}
for (int i = 1; i <= B; i++)
{
scanf("%d",&b[i]);
}
cnt = 1;
for (int i = 1; i <= m; i++)
{
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);
}
cntn = cnt + 1;
for (int i = 1; i <= B; i++)
{
if ((b[i] & 1) == 0)
for (int j = 1; j <= B; j++)
if ((b[j] & 1) == 1 && count(b[i] | b[j]) % 2 == 0)
{
add(i,j,1);
}
}
s = 0;
t = B + 1;
for (int i = 1; i <= B; i++)
{
if ((b[i] & 1) == 0)
add(s,i,1);
else add(i,t,1);
}
for (int i = s; i <= t; i++)
use[i] = 1;
dinic();
for (int i = 1; i <= B; i++)
use[i] = 0;
int maxB = B - ans;
for (int i = 1; i <= A; i++)
{
int tot = 0;
for (int j = next[i]; j; j = e[j].next)
{
use[e[j].to] = 1;
tot ++;
}
ans = 0;
clear();
dinic();
maxB = std::max(maxB,tot - ans + 1);
for (int j = next[i]; j; j = e[j].next)
{
use[e[j].to] = 0;
}
}
for (int i = 1; i < A; i++)
{
for (int j = i + 1; j <= A; j++)
{
if ((a[i] ^ a[j]) % 2 == 1)
{
for (int k = next[i]; k; k = e[k].next)
{
use[e[k].to]++;
}
for (int k = next[j]; k; k = e[k].next)
{
use[e[k].to]++;
}
int tot = 0;
for (int k = 1; k <= B; k++)
if (use[k])
{
use[k]--;
if (use[k])
tot++;
}
clear();
ans = 0;
dinic();
maxB = std::max(maxB,tot - ans + 2);
for (int k = next[i]; k; k = e[k].next)
{
use[e[k].to] = 0;
}
}
}
}
printf("%d\n",maxB);
}