首先抛开每个朋友参与游戏的次数限制,在每一天的时候,都尽量去选参与人数最少的朋友,如果这样还超出了限制,那么就判定无解。于是写出下面的代码:
void solve()
{
int n, m;
cin >> n >> m;
vector<int> f(n + 1, 0), ans(m, 0);
for(int i = 0; i < m; i ++ )
{
int k;
cin >> k;
vector<int> v;
for(int j = 0; j < k; j ++ )
{
int x;
cin >> x;
v.eb(x);
}
int mi = LLONG_MAX;
int id = LLONG_MAX;
for(auto &k : v)
{
if(mi >= f[k])
{
mi = f[k];
id = k;
}
}
ans[i] = id;
f[id] ++;
}
for(int i = 1; i <= n; i ++ )
{
if(f[i] > (m + 1) / 2)
{
cout << "NO" << "\n";
return;
}
}
cout << "YES" << "\n";
for(int i = 0; i < m; i ++ )
{
cout << ans[i] << ' ';
}
cout << "\n";
return;
}
随后WA,实际上,如果某一天所有朋友参与次数都相等,比如第一天,所有朋友都参与了零次,那么我们怎么选会对答案产生影响,这也是以上代码忽略的地方(直接就选了第一个朋友)。
如何产生影响的呢?如果后面有些天只有那一个朋友能选,那只能选这个朋友,如果这样的情况出现了⌈m / 2⌉次,而在第一天的时候,也选了这个朋友(而恰好第一天还可以选别的朋友),那就会出现误判。
所以尝试着先处理这些只有一个朋友的情况,随后再贪心地选参与人数最少的朋友,得到AC。
void solve()
{
int n, m;
cin >> n >> m;
vector<int> f(n + 1, 0), ans(m, 0);
vector<vector<int>> v(m);
for(int i = 0; i < m; i ++ )
{
int k;
cin >> k;
for(int j = 0; j < k; j ++ )
{
int x;
cin >> x;
v[i].eb(x);
}
if(k == 1)
{
ans[i] = v[i][0];
f[v[i][0]] ++;
}
}
for(int i = 0; i < m; i ++ )
{
if(v[i].size() == 1) continue;
int mi = LLONG_MAX;
int id = LLONG_MAX;
for(auto &k : v[i])
{
if(mi >= f[k])
{
mi = f[k];
id = k;
}
}
ans[i] = id;
f[id] ++;
}
for(int i = 1; i <= n; i ++ )
{
if(f[i] > (m + 1) / 2)
{
cout << "NO" << "\n";
return;
}
}
cout << "YES" << "\n";
for(int i = 0; i < m; i ++ )
{
cout << ans[i] << ' ';
}
cout << "\n";
return;
}
(这并不是一篇严格意义上的题解,只是记录一下自己的想法,实际上,虽然AC了,但是本人暂时没能完全理解这道题)