Problem Statement
There is a simple graph with N vertices numbered 1 to N and M edges numbered 1 to M. Edge i connects vertices
u
i
u_i
ui and
v
i
v_i
vi. Each vertex has one lamp on it. Initially, all the lamps are off.
Determine whether it is possible to turn exactly K lamps on by performing the following operation between 0 and M times, inclusive.
Choose one edge. Let u and v be the endpoints of the edge. Toggle the states of the lamps on u and v. That is, if the lamp is on, turn it off, and vice versa.
If it is possible to turn exactly K lamps on, print a sequence of operations that achieves this state.
Constraints
1
≤
N
≤
2
×
1
0
5
1 \leq N \leq 2\times 10^5
1≤N≤2×105
0
≤
M
≤
min
(
2
×
1
0
5
,
N
(
N
−
1
)
2
)
0 \leq M \leq \min(2\times 10^5, \frac{N(N-1)}{2})
0≤M≤min(2×105,2N(N−1))
0
≤
K
≤
N
0\leq K \leq N
0≤K≤N
1
≤
u
i
≤
b
i
1\leq u_i \leq b_i
1≤ui≤bi
The given graph is simple. All input values are integers.
思路
首先,能打开灯的个数必为偶数(两个灯同时熄灭或打开,一个熄灭一个被打开,变化为-2,0,+2)。
接下来,遍历每个连通域,以第一个被访问的结点为根结点扩展得到子树(连通域本身有环也没关系,可以让dfs过程将其限制为树):对于每个叶子结点,若它是熄灭的,则操作它与其父节点,显然这个操作带来的结果是让打开的灯树+0或+2,然后将该结点从子树中移除即可。该过程持续值该连通域操作完毕或打开灯数已达目标。
Code
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
typedef struct Edge {
int id, to;
};
vector<vector<Edge>> edges(200005);
vector<int> ans;
bool light[200005];
bool visit[200005];
int cnt;
int k;
void dfs(int root) {
visit[root] = true;
for (auto &e: edges[root]) {
if (visit[e.to])
continue;
dfs(e.to);
if (cnt<k&&!light[e.to]) {
++cnt;
light[root] = !light[root];
light[e.to] = !light[e.to];
if (light[root])
++cnt;
else
--cnt; // 注意
ans.push_back(e.id);
}
}
}
int main() {
int n,m;
cin>>n>>m>>k;
int u,v;
for (int i=1;i<=m;i++) {
cin>>u>>v;
edges[u].push_back({i,v});
edges[v].push_back({i,u});
}
memset(visit,0,sizeof(visit));
memset(light,0,sizeof(light));
if (k%2!=0) // 奇数绝不可能
cout << "No" << endl;
else {
cnt = 0;
// 可能有多个连通域
for (int i=1;i<=n&&cnt<k;i++) {
if (visit[i])
continue;
dfs(i);
}
if (cnt==k) { // 可能无法打开k盏灯
cout << "Yes" << endl;
cout << ans.size() << endl;
for (int i=0;i<ans.size();i++)
cout << ans[i] << ' ';
cout << endl;
} else
cout << "No" << endl;
}
}