题意:N个男孩和N个女孩要开个跳舞party,把愿意一块跳舞的男孩女孩的编号给出,男孩女孩最多和K个不喜欢的女孩男孩跳舞,问最多举行几轮(每一轮的舞伴不同)
解析:拆点,二分答案—建图:源点到男孩1的边容量为二分的值,女孩1到汇点的边容量为二分的值,男孩1到喜欢女孩1的边容量为1,男孩1到男孩2的边容量为k,男孩2到不喜欢女孩2的边容量为1,女孩2到女孩1的边容量为k,求最大流#include <cstdio>
#include <cstring>
#define INF 0x3f3f3f3f
#define max(a,b) (a) > (b) ? (a) : (b)
#define min(a,b) (a) < (b) ? (a) : (b)
using namespace std;
const int MAXN = 500;
struct Edge{
int v,cap,next;
Edge(){}
Edge(int _v,int _cap,int _next):v(_v),cap(_cap),next(_next){}
}edge[2*MAXN*MAXN];
int n,m;
int head[MAXN],size;
int h[MAXN],agree[MAXN][MAXN];
int N,M,K,src,sink;
inline void init(){
size = 0;
memset(head,-1,sizeof(head));
}
inline void add_edge(int u,int v,int x){
edge[size] = Edge(v,x,head[u]);
head[u] = size++;
edge[size] = Edge(u,0,head[v]);
head[v] = size ++;
}
inline int BFS(){
int tou,tail;
int u,v,w,tep;
int que[MAXN];
memset(h,-1,sizeof(h));
h[src] = 0;
tou = tail = 0;
que[tail++] = src;
while (tail > tou){
u = que[tou++];
for(int i = head[u]; i != -1; i = edge[i].next){
v = edge[i].v;
w = edge[i].cap;
if (h[v] == -1 && w > 0){
h[v] = h[u] + 1;
que[tail++] = v;
}
}
}
return h[sink] != -1;
}
inline int DFS(int u,int flow){
if(u == sink)return flow;
int i,tmpf,minf,v,w;
tmpf = 0;
for(i = head[u]; i != -1; i = edge[i].next){
v = edge[i].v;
w = edge[i].cap;
if(h[v] == h[u] + 1 && w > 0 && tmpf < flow && (minf = DFS(v,min(w,flow-tmpf)))){
edge[i].cap -= minf;
if(i%2 == 0)edge[i+1].cap += minf;
else edge[i-1].cap += minf;
tmpf += minf;
}
}
if(tmpf == 0)h[u] = -1;
return tmpf;
}
inline int dinic(){
int t,ans = 0;
while (BFS()){
while (t = DFS(src,INF))ans += t;
}
return ans;
}
inline bool check(int mid){
init();
for(int i = 1; i <= n; ++i)add_edge(src,i,mid);
for(int i = 1; i <= n; ++i)add_edge(3*n+i,sink,mid);
for(int i = 1; i <= n; ++i)add_edge(i,n+i,K);
for(int i = 1; i <= n; ++i)add_edge(i+2*n,i+3*n,K);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j){
if(agree[i][j]){
add_edge(i,3*n+j,1);
}
else add_edge(i+n,2*n+j,1);
}
if(dinic() >= n*mid){
return true;
}
else return false;
}
inline int solve(){
int high = n,low = 0;
int mid;
while (low <= high){
mid = (low+high)/2;
if(check(mid))low = mid + 1;
else high = mid - 1;
}
return high;
}
int main(){
int cas;
scanf("%d",&cas);
while (cas --){
scanf("%d%d%d",&n,&m,&K);
int a,b,c;
src = 0;sink = 4*n + 1;
N = 4*n + 2;
memset(agree,0,sizeof(agree));
while (m --){
scanf("%d%d",&a,&b);
agree[a][b] = 1;
}
int ans = solve();
printf("%d\n",ans);
}
return 0;
}