链接:https://codeforces.com/contest/1484/problem/C
题意:
有m天和n个朋友,给出每一天哪些朋友是空闲的,每天邀请一个朋友,不能有朋友的出现次数超过
m
2
\frac{m}{2}
2m,输出任一答案,如果没有答案输出NO。
思路一:贪心
优先选择空闲朋友少的天,对于每一天选择出现次数最少的朋友。
代码:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn = 100005;
vector<int> f[maxn];
int vis[maxn];
int ans[maxn];
int main()
{
int t,n,m,k;
cin>>t;
while (t--)
{
pair<int,int> so[maxn];
cin>>n>>m;
int ff,flag = 1;
memset(vis,0,sizeof(vis));
memset(ans,0,sizeof(ans));
for(int i = 1; i <= m; i++){
f[i].clear();
cin>>k;
so[i].first = k;
so[i].second = i;
for(int j = 1;j <= k; j++){
cin>>ff;
f[i].push_back(ff);
}
}
sort(so + 1,so + m + 1);
// for(int i = 1;i <= m;i++)
// cout<<so[i].second<<endl;
// cout<<"**"<<endl;
int no = INF;
int po = 0;
for(int c = 1;c <= m ;c++){
int i = so[c].second;
if(f[i].size() == 1)
po = f[i][0];
else{
no = INF;
for(int j = 0;j < f[i].size(); j++){
int v = f[i][j];
if(vis[v] < no){
no = vis[v];
po = v;
}
}
}
ans[i] = po;
vis[po]++;
if(vis[po] > (m + 1) / 2){
flag = 0;
break;
}
}
if(flag){
cout<<"YES"<<endl;
for(int i = 1;i <= m - 1; i++)
cout<<ans[i]<<" ";
cout<<ans[m]<<endl;
}
else
cout<<"NO"<<endl;
}
return 0;
}
思路二:
可以把这个题目当做一个网络流来做。
将天数作为编号为1~m的点,朋友作为编号为m+1~m+n的点,再添加一个起始s点为n+m+1,终点t为s+1,转化为二分图匹配。
对于所有的起始点和天数点,连一条流量为1的边,对应的天数和朋友连一条流量为1的边,为了满足次数小于 m 2 \frac{m}{2} 2m,让所有朋友和终点的连边的流量为 m 2 \frac{m}{2} 2m。
对这个图求他的最大匹配,如果匹配等于m说明有解,该天对应的答案就是两个点之间权值变为0的点。
一开始用的FF算法,结果超时了,FF的算法时间复杂度是 O ( F E ) O(FE) O(FE),不适用于流量太大的网络,换成了dinic
代码(dinic):
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
#define INF 0x3f3f3f3f
struct edge
{
int to,cap,rev;
void add(int a,int b,int c){
to = a,cap = b,rev = c;
}
};
int level[maxn],iter[maxn],ans[maxn];
vector<edge> g[maxn];
void add_edge(int u,int v,int cap){
edge e1,e2;
e1.add(v,cap,g[v].size());
g[u].push_back(e1);
e2.add(u,0,g[u].size() - 1);
g[v].push_back(e2);
}
void bfs(int s)
{
memset(level,-1,sizeof(level));
queue<int> q;
level[s] = 0;
q.push(s);
while (!q.empty())
{
int u = q.front();
q.pop();
for(int i = 0;i < g[u].size(); i++){
edge &e = g[u][i];
if(e.cap > 0 && level[e.to] < 0){
level[e.to] = level[u] + 1;
q.push(e.to);
}
}
}
}
int dfs(int u,int t,int f){
if(u == t)
return f;
for(int &i = iter[u];i < g[u].size() ;i++){
edge &e = g[u][i];
if(e.cap > 0 && level[u] < level[e.to]){
int d = dfs(e.to,t,min(f,e.cap));
// cout<<d<<endl;
if(d > 0){
e.cap -= d;
g[e.to][e.rev].cap += d;
return d;
}
}
}
return 0;
}
int max_flow(int s,int t){
int flow = 0;
for(;;){
bfs(s);
if(level[t] < 0){
return flow;
cout<<"flow"<<flow<<endl;
}
memset(iter,0,sizeof(iter));
int f;
while(f = dfs(s,t,INF) > 0)
flow += f;
}
return flow;
}
void init(int x)
{
for(int i = 1;i <= x; i++)
g[i].clear();
// memset(ans,0,sizeof(ans));
}
int main()
{
int T,n,m;
cin>>T;
while (T--)
{
int k,j,s,t;
cin>>n>>m;
s = n + m + 1,t = s + 1;
init(t);
for(int i = 1;i <= m; i++){
cin>>k;
while(k--){
cin>>j;
add_edge(i,m + j,1);
}
add_edge(s,i,1);
}
for(int i = 1; i <= n; i++)
add_edge(m + i,t,(m + 1) / 2);
int an = max_flow(s,t);
// cout<<an<<endl;
if(an == m){
cout<<"YES"<<endl;
for(int i = 1; i <= m; i++){
for(int j = 0;j < g[i].size(); j++){
if(g[i][j].cap == 0 )
ans[i] = g[i][j].to - m ;
}
}
for(int i = 1;i <= m; i++)
cout<<ans[i] <<" ";
cout<<endl;
}
else
cout<<"NO"<<endl;;
}
return 0;
}
超时的FF也贴一下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
#define INF 0x3f3f3f3f
struct edge
{
int to,cap,rev;
void add(int a,int b,int c){
to = a,cap = b,rev = c;
}
};
vector<edge> g[maxn];
int vis[maxn],ans[maxn];
int T,n,m,k;
void add(int u,int v,int cap){
edge e1,e2;
e1.add(v,cap,g[v].size());
g[u].push_back(e1);
e2.add(u,0,g[u].size() - 1);
g[v].push_back(e2);
}
int dfs(int u,int t,int f)
{
if(u == t)
return f;
vis[u] = 1;
for(int i = 0;i < g[u].size(); i++){
edge &e = g[u][i];
// cout<<e.to<<endl;
if(!vis[e.to] && e.cap > 0){
int d = dfs(e.to,t,min(f,e.cap));
if(d > 0){
e.cap -= d;
g[e.to][e.rev].cap += d;
// cout<<d<<endl;
return d;
}
}
}
// puts("0");
return 0;
}
int max_flow(int s,int t)
{
int res = 0;
for(;;){
memset(vis,0,sizeof(vis));
int f = dfs(s,t,INF);
if(f == 0) return res;
res += f;
}
}
void init(int x)
{
for(int i = 1;i <= x; i++)
g[i].clear();
// memset(ans,0,sizeof(ans));
}
int main()
{
ios::sync_with_stdio(false);
cin>>T;
while(T--){
int f;
cin>>n>>m;
int s = n + m + 1,t = s + 1;
// cout<<s<<t<<endl;
init(t);
for(int i = 1;i <= m; i++){
cin>>k;
for(int j = 1;j <= k; j++){
cin>>f;
add(i, f + m,1);
}
add(s,i,1);
}
for(int i = 1;i <= n; i++)
add(m + i, t, (m + 1) / 2);
int an = max_flow(s,t);
// cout<<an<<endl;
if(an == m){
cout<<"YES"<<endl;
for(int i = 1; i <= m; i++){
for(int j = 0;j < g[i].size(); j++){
if(g[i][j].cap == 0 )
ans[i] = g[i][j].to - m ;
}
}
for(int i = 1;i <= m; i++)
cout<<ans[i] <<" ";
cout<<endl;
}
else
cout<<"NO"<<endl;
}
}