【ZOJ3933 The 16th Zhejiang University Programming ContestG】【费用流】Team Formation 最多组队条件下女

Team Formation

Time Limit: 2 Seconds        Memory Limit: 65536 KB        Special Judge

For an upcoming programming contest, Edward, the headmaster of Marjar University, is forming several two-man teams from students of his university.

There are n students in the university numbered from 1 to n. There are two groups of students in the university and each student belongs to exactly one of the groups. For each student in the university, he/she has a list of students whom he/she will never form a team with. For two students a and b, if b is in a's list, a is also in b's list.

Edward will only form high-performance teams. A high-performance team is a team which consists of two students from different groups who are willing to form a team. In addition, Edward wants as many as possible girls to participate in the contest. You, as Edward's secretary, need to form as many high-performance teams as possible and at the same time maximize the number of girls in the teams.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains an integer n (1 ≤ n ≤ 500) -- the number of students.

The second line contains a binary string of length n. If the i-th character is 0 then i-th student is in the first group, otherwise the student is in the second group.

The third line contains a binary string of length n. If the i-th character is 0 then i-th student is a girl, otherwise the student is a boy.

In the following n lines, each line starts with an integer m followed with m distinct integers, denoting the list of i-th student.

Output

For each case, output two integers a and b denoting the number of high-performance teams and the number of girls.

In the next a lines, each contains two integers xi and yi denoting the students in i-th team.

If there are multiple solutions, you can output any of them.

Sample Input
1
3
101
000
0
0
0
Sample Output
1 2
1 2

Author:  LIN, Xi
Source:  The 16th Zhejiang University Programming Contest

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 505, M = N*N*6, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int casenum, casei;
int id, ST, ED;
int first[N];
int w[M], c[M], cap[M], cost[M], nxt[M];
int f[N];
int pe[N];
bool e[N];
void ins(int x, int y, int cap_, int cost_)
{
	w[++id] = y;
	cap[id] = cap_;
	cost[id] = cost_;
	nxt[id] = first[x];
	first[x] = id;

	w[++id] = x;
	cap[id] = 0;
	cost[id] = -cost_;
	nxt[id] = first[y];
	first[y] = id;
}
int q[int(2e5)];
int h, t;
struct node
{
	int x, dis;
	node(int x, int dis) :x(x), dis(dis) {}
	bool operator < (const node&b)const
	{
		return dis > b.dis;
	}
};
priority_queue<node>Q;
void inq(int x, int cost_, int pe_)
{
	if (cost_ >= f[x])return;
	f[x] = cost_;
	pe[x] = pe_;
	Q.push(node(x, cost_));
}
bool dijkstra()
{
	while (!Q.empty())Q.pop();
	MS(f, 63);
	MS(e, 0);
	cap[0] = ms63;
	inq(ST, 0, 0);
	while (!Q.empty())
	{
		int x = Q.top().x; Q.pop();
		if (e[x])continue; e[x] = 1;
		if (x == ED)return 1;
		for (int z = first[x]; z; z = nxt[z])
		{
			if (cap[z])inq(w[z], f[x] + cost[z], z);
		}
	}
	return f[ED] < ms63;
}
bool spfa()
{
	MS(e, 0);
	MS(f, 63);
	cap[0] = ms63;
	h = t = 1e5;
	inq(ST, 0, 0);
	while (h<t)
	{
		int x = q[h++]; e[x] = 0;
		for (int z = first[x]; z; z = nxt[z])
		{
			if (cap[z])inq(w[z], f[x] + cost[z], z);
		}
	}
	return f[ED]<ms63;
}
int edge;
void MCMF()
{
	int maxflow = 0;
	int mincost = 0;
	//while (spfa())
	while(dijkstra())
	{
		int flow = ms63;
		int x = ED;
		while (x != ST)
		{
			gmin(flow, cap[pe[x]]);
			x = w[pe[x] ^ 1];
		}
		maxflow += flow;
		mincost += f[ED] * flow;
		x = ED;
		while (x != ST)
		{
			cap[pe[x]] -= flow;
			cap[pe[x] ^ 1] += flow;
			x = w[pe[x] ^ 1];
		}
	}
	//跑完最小费用最大流,maxflow就是组数,mincost就是男生人数,maxflow*2-mincost就是女生人数
	printf("%d %d\n", maxflow, maxflow*2-mincost);
	for (int i = 2; i <= edge; i += 2)if (cap[i] == 0)
	{
		printf("%d %d\n", w[i ^ 1], w[i]);
	}
}
char group[N];
char sex[N];
int n;
int main()
{
	scanf("%d", &casenum);
	for (casei = 1; casei <= casenum; ++casei)
	{
		memset(first, 0, n + 2 << 2); id = 1;
		scanf("%d", &n);
		ST = 0;
		ED = n + 1;
		scanf("%s", group + 1);
		scanf("%s", sex + 1);
		for (int i = 1; i <= n; ++i)
		{
			MS(e, 1); e[i] = 0;
			int g; scanf("%d", &g);
			while (g--)
			{
				int x; scanf("%d", &x);
				e[x] = 0;
			}
			if (group[i] == '0')for (int j = 1; j <= n; ++j)if (e[j] && group[j] == '1')
			{
				ins(i, j, 1, 0);
			}
		}
		edge = id;
		for (int i = 1; i <= n; ++i)
		{
			if (group[i] == '0')ins(ST, i, 1, sex[i]=='1');
			else ins(i, ED, 1, sex[i]=='1');
		}
		MCMF();
	}
	return 0;
}
/*
【题意】
有n(500)个人,这些人每个人不是属于group0就是属于group1。不是女生('0')就是男生('1')
每个人有些人是不想分组的
我们希望使得这n个人分尽可能多的组,
在这个条件下使得女生的人数尽可能多

【类型】
费用流

【分析】
显然这题可以费用流
源点向组0建边,容量为1费用为0
组0的人向组1的人中不是讨厌的人建边,容量为1,费用为2-女生数
组1向汇点建边,容量为1费用为0
然后跑最小费用最大流即可。

当然建图还可以——
源点向组0建边,容量为1费用为:男生?1:0
组0的人向组1的人中不是讨厌的人建边,容量为1,费用为0
组1向汇点建边,容量为1费用为:男生?1:0

不过没什么差别。

【时间复杂度&&优化】
这题很卡常数。
我们可以引用spfa的SLF优化,
或者引用dijkstra费用流
所谓dijkstra费用流,就是用dijkstra代替spfa

【数据】
100
4
1100
0000
0
0
0
0

*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值