您的位置:首页 > 理论基础 > 计算机网络

网络流 UVA 11544 Recruiter's Problem

2014-07-30 08:16 344 查看
Problem G

Recruiter's Problem 

Input: 
Standard Input
Output: Standard Output
 
You are working as an HR officer in “Nice Computer Programmer's Company(NCPC)”. You have to hire a lot of people in a very short period. The hiring process is simple. Interview all the applicants, grade them, select the ones who
survived the interview board, then assign them to projects. So, you can see, the hardest job is interviewing the candidates, and find who is capable of working in NCPC. Don'tworry, you don't need to do that. You will be given a list of candidates, who survived
the interview, sorted according to their scores given by the interviewers. You need to to assign them to different projects. Simple, isn't it? But, unfortunately, this is not as easy as it seems to be.
There are N candidates and M different projects, each project requiring ri programmers. You know that, not everyone is interested in working
in any position. For example, not everyone likes the job of tester, or QA Engineer. Every applicant has given you a list of job,they can work, according to their preferences. Since, NCPC needs to hire a lot of people, they have decided to recruit maximum number
of programmers, they can from current candidates.
There can be more than one way to select maximum number of candidates. That is where their grades and preferences comes into play. If there is more than one way to fill the maximum number of spot, give the highest ranked candidate
his most preferred position you can. If there is still more than one way, give the second highest ranked candidate, his most preferred position possible, and so on.
 
Input
 
First line contains T (T ≤ 61), the number of test cases. Each test case starts with two integer N (N<=50) and M (M<=50), the number
of candidates, and the number of available projects. The following line contains M integers ri (ri ≤ 50, 

), the
number of open spots in project i. The next N lines describe the preferences of candidate i. Each of the lines starts with an integer K (K ≤ M), followed
byK integer pj (j = 1...K), the projects i-th applicant is interested to work, sorted by his/her preference (p1 is the most preferred project, andpK is
the least preferred). Applicant 1, is the highest ranked applicant, and applicant N is the least ranked. for all candidates, pj <= M, and no job appear in the list twice
 

Output

 
For each test case output the case number, followed by the maximum number of applicant you can recruit, L. This is followed by L lines, each containing two integers, a and p,
where ath applicant is recruited for project p.

Sample Input                              Output for Sample Input

1

3 3

1 1 1

2 1 2

2 3 2

2 3 2

Case #1:

3 applicant(s) can be hired.

1 1

2 3

3 2

 

Problemsetter: Manzurur Rahman Khan
Special Thanks to: Sabbir Yousuf Sanny

思路:源点向每个部门连一条边,容量为部门最大容人量,某个人有意愿进入某个部门,就从部门连一条边到这个人,容量为1,每个人连一条边到汇点,容量为1。 我们先算出最大流,然后根据最大流开始枚举每个人的意愿,如果强制某个人的意愿后任然能得到同样的大小最大流表示是可行的,直接开始枚举下一个人的意愿。竟然不会超时。。。。



代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int maxn=50*2+50;
const int inf=1e8;

int cap[maxn][maxn],flow[maxn][maxn];
vector<int> G[maxn];

void add(int u,int v,int c)
{
cap[u][v]=c; cap[v][u]=0;
G[u].push_back(v);
G[v].push_back(u);
}

bool done[maxn];
struct ISAP
{
int d[maxn], p[maxn], num[maxn], cur[maxn];
int n, s, t;
void init(int n) { this->n = n; }

int Augment()
{
int x = t, a = inf;
while (x != s)
{
a = min(a, cap[p[x]][x] - flow[p[x]][x]);
x = p[x];
}
x = t;
while (x != s)
{
flow[p[x]][x]+=a;
flow[x][p[x]] -= a;
x = p[x];
}
return a;
}

int q[maxn],front,rear;
void bfs()
{
for (int i = 0; i<n; ++i) d[i] = inf;
front=rear=0; q[rear++]=t;
d[t] = 0;
while (front<rear)
{
int x = q[front++];
for (int i = 0; i<G[x].size(); ++i)
{
int y=G[x][i];
if (cap[x][y]>0 || d[y] <= d[x] + 1) continue;
if (done[y] || cap[y][x]==0) continue;
d[y] = d[x] + 1;
q[rear++]=y;
}
}
}

int maxflow(int s, int t)
{
this->s = s, this->t = t;
memset(num, 0, sizeof(num));
memset(cur, 0, sizeof(cur));
bfs();
for (int i = 0; i<n; ++i)
if (d[i] != inf) ++num[d[i]];
int ret = 0, x = s;
while (d[s]<n)
{
if (x == t)
{
ret += Augment();
x = s;
}
int ok = 0;
for (int i = cur[x]; i<G[x].size(); ++i)
{
int y=G[x][i];
if (cap[x][y]>flow[x][y]&&d[y] + 1 == d[x])
{
ok = 1;
cur[x] = i;
p[y] = x;
x = y;
break;
}
}
if (!ok)
{
int m = n - 1;
for (int i = 0; i<G[x].size(); ++i)
{
int y=G[x][i];
if (cap[x][y]>flow[x][y]) m = min(m, d[y]);
}
if (--num[d[x]] == 0) break;
++num[d[x] = m + 1];
cur[x] = 0;
if (x != s) x = p[x];
}
}
return ret;
}
}solver;

int N,M,s,t;
vector<int> p[maxn];
void input()
{
scanf("%d%d",&N,&M);
s=0,t=N+M+1; solver.init(t+1);
for(int i=0;i<maxn;++i) p[i].clear();
for(int i=0;i<maxn;++i) G[i].clear();
memset(cap,0,sizeof(cap));
for(int i=1;i<=M;++i) {
int x; scanf("%d",&x);
add(s,i,x);
}
for(int i=M+1;i<=N+M;++i) {
int K; scanf("%d",&K);
add(i,t,1);
while(K--) {
int x; scanf("%d",&x);
add(x,i,1);
p[i].push_back(x);
}
}
}

void clear()
{
memset(flow,0,sizeof(flow));
}

int mtch[maxn];
void solve()
{
clear(); memset(done,0,sizeof(done));
int maxflow=solver.maxflow(s,t);
printf("%d applicant(s) can be hired.\n",maxflow);
memset(mtch,-1,sizeof(mtch));
int cnt=0;
for(int u=M+1;u<=M+N;++u) {
done[u]=true; bool ok=false;
for(int j=0;j<p[u].size();++j) {
clear();
int v=p[u][j];
if(cap[s][v]<=0) continue;
--cap[s][v];
// if(flow[v][u]!=0) { mtch[u]=v; break; }
int k=solver.maxflow(s,t);
// printf("%d\n",k);
if(k+cnt+1==maxflow)
{
ok=true;
mtch[u]=v;
break;
} else ++cap[s][v];
}
if(ok) ++cnt;
}
for(int i=M+1;i<=M+N;++i) {
if(mtch[i]==-1) continue;
printf("%d %d\n",i-M,mtch[i]);
}
}

int main()
{
int T;cin>>T; int Cas=0;
while(T--) {
++Cas;
input();
printf("Case #%d:\n",Cas);
solve();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: