题意:
给你n个点,m条双向边
构成一个重边无环的图
每个顶点有的值为{-1,0,1}
现在要你选择保留这个图中的某些边(可以是0条)
使得每个顶点满足以下两个条件之一
1. d[i] = -1
2.d[i] = dgree[i] % 2 (dgree[i] 为该点的度数)
请问是否有答案,无则输出-1,有则输出其中一个答案,有几条边,且是第几条边
题解:
这是一个无环的图,我们可以把它当成一颗棵树
然后从子节点开始判断,父节点与子节点的边取不取,如果叶子节点为1,那么该边一定取,取完之后,那么我们可以将节点的值进行取反,这样性质是一样的。这样一直操作,到根节点,只要根节点满足条件就一定有解,那么我们可以直接把-1的点拿来当根节点,这样就一定有解。
AC_Code:
/*
Algorithm: dfs序
Author: anthony1314
Creat Time:
Time Complexity:
*/
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<cstring>
#include<cstdio>
//#include<bits/stdc++.h>
#define ll long long
#define maxn 300005
#define mod 1e9 + 7
#define line printf("--------------");
using namespace std;
struct edge {
int v, from;
} e[maxn*2];
int first[maxn], d[maxn], n, m, ans = 0, tot = 0;
bool vis[maxn], a[maxn*2];
int addedge(int u, int v) {
tot++;
e[tot].v = v;
e[tot].from = first[u];
first[u] = tot;
tot++;
e[tot].v = u;
e[tot].from = first[v];
first[v] = tot;
}
int dfs(int x){
vis[x] = true;
for(int i = first[x];i; i = e[i].from){
int v = e[i].v;
if(!vis[v]){
if(dfs(v) & 1){
a[i] = true;
ans++;
if(d[x] != 2){
d[x] = 1 - d[x];//取反
}
}
}
}
return d[x];
}
int main() {
scanf("%d %d", &n, &m);
int flag = 0;
for(int i = 1; i <= n; i++){
scanf("%d", &d[i]);
if(d[i] == -1){
flag = i;
d[i] = 2;
}
}
int u, v;
for(int i = 0; i < m; i++){
scanf("%d %d", &u, &v);
addedge(u, v);
}
if(flag){
dfs(flag);
}else {
if(dfs(1) & 1){
printf("-1\n");
return 0;
}
}
printf("%d\n", ans);
for(int i = 1; i <= tot; i+=2){//因为双向边
if(a[i] || a[i+1]){
printf("%d ",i/2 + 1);
}
}
return 0;
}