K - Two Sides of the Same Coin
题目很长,只后面那一段才有用, 题意是需要两个人出一道题,一个做statements,另一个做testdata,而anthing的人可以做任意一种,但人不能同时出不同的题,求最多能出多少道题
这是典型的最大二分匹配
#include <cstring>
#include <cstdio>
#include <string>
#include <iostream>
#include <algorithm>
#include <map>
#include <math.h>
#include <vector>
using namespace std;
const int N=1005;
struct node{
string name;
string pos;
int rank;
}per[N]; //人的信息
vector<int> G[N]; //保存图
//string str[N];
int used[N]; //查找增广路
int match[N]; //记录匹配顶点
int c=0;
bool dfs(int v){ //dfs 查找
used[v]=1;
for(int i=0;i<G[v].size();i++){
int u=G[v][i]; //可以与该顶点匹配的顶点
int w=match[u]; //判断可已有匹配的点
if(w<0 || !used[w] && dfs(w)){ //如果还没有匹配
match[v]=u; //或还未查找到的顶点v并且与此顶点匹配的顶点有增广路,可与另一顶点匹配
match[u]=v;
return true;
}
}
return false;
}
int bm(int n)
{
int res=0;
memset(match,-1,sizeof match); //查找匹配
for(int i=0;i < n;i++)
{
if(match[i]<0){ //若还未匹配
memset(used,0,sizeof used); //重新查找
if(dfs(i)){
res++; //有匹配则加
}
}
}
return res;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++){
G[i].clear();
cin>>per[i].name>>per[i].pos>>per[i].rank;
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
if(i==j) continue;
if(abs(per[i].rank-per[j].rank)!=2) continue;
if(per[i].pos=="statements"&&per[j].pos=="statements" || per[i].pos=="testdata"&& per[j].pos=="testdata")
continue;
G[i].push_back(j); //符合要求的顶点入集合
}
c=bm(n);
cout<<c<<endl;
for(int i=0;i<n;i++){
if(match[i]<0 || i>=match[i]){ //没有匹配的顶点
continue; //i>=match[i] 是指只需找匹配的一边集合即可另一半有重复的匹配
}
int x=match[i];
if(per[i].pos=="statements" || per[x].pos=="testdata"){
cout<<per[i].name<<" "<<per[x].name<<endl;
}
else{
cout<<per[x].name<<" "<<per[i].name<<endl;
}
}
return 0;
}