有一个联通无向图,每个点有要求:度必须是偶数、必须是奇数或任意
求是否能找出一个包含所有点的子图满足所有点的要求,若能,输出这个子图的边集
首先,看到无向连通图图上的问题,一个方向就是建DFS生成树。
将图中的边转化为树边和非树边,非树边对答案的影响转化为生成树上的覆盖。
然而这道题简单到甚至不用考虑非树边....考虑非树边还让我最开始想偏了....
然后我们会想到利用树的性质:子树独立。所以可以考虑如何把一个子树内的点全部满足其条件。先递归处理u的所有儿子,回溯时若u以满足奇偶限制则直接回溯,否则将\((u,f(u))\)选入集合,然后回溯。这似乎是一种比较常见的树上构造方法
显然,这样处理只有根可能奇偶性不满足。
若满足直接输出。
否则,若全局没有-1,则输出-1。
否则,随便找一个-1的点,记作u,将u到root的边的选取情况取反(选变不选,不选变选),然后输出就好了。
输出我用的是记录每个点和它父亲的边是输入的哪一条,然后选不选
稍微卡卡常貌似是提交时的最优解,但很快就会被刷下去的
这里放上我丑陋的代码
#include<bits/stdc++.h>
#define ri register int
#define ll long long
using namespace std;
const int maxn = 3e5 + 10;
int d[maxn],du[maxn],head[maxn],head1[maxn],ed[maxn],f[maxn],n,m,tot = 1,tot1;
bool chos[maxn],vis[maxn];
struct edge{
int to,nex;
}e[maxn<<1],e1[maxn<<1];
inline void add(int u,int v){
e[++tot] = (edge){v,head[u]};
head[u] = tot;
}
inline int rd(){
int res = 0,f = 0;
char ch = getchar();
for(;ch > ‘9‘ || ch < ‘0‘;ch = getchar()) if(ch == ‘-‘) f = 1;
for(;ch >= ‘0‘ && ch <= ‘9‘;ch = getchar()) res = (res<<3) + (res<<1) + ch - 48;
return f ? -res : res;
}
void dfs(int u){
vis[u] = 1;
for(ri i = head[u];i;i = e[i].nex){
int v = e[i].to;
if(vis[v]) continue;
ed[v] = i >> 1;
f[v] = u;
e1[++tot1] = (edge){v,head1[u]};
head1[u] = tot1;
dfs(v);
}
}
void solve(int x){
for(ri i = head1[x];i;i = e1[i].nex) solve(e1[i].to);
if(du[x] == d[x] || d[x] == -1 || x == 1) return;
chos[x] = 1;
du[x] ^= 1; du[f[x]] ^= 1;
return;
}
void change(int x){//把x到root的边的状态全部取反
while(x != 1){
chos[x] ^= 1;
du[x] ^= 1; du[f[x]] ^= 1;
x = f[x];
}
return;
}
int ans[maxn],cnt = 0;
int cp = -1;
void write(int x){
if(x > 9) write(x / 10);
putchar(x % 10 + 48);
}
void prin(int x){
if(x < 0) putchar(‘-‘),x = -x;
write(x);
}
int main(){
n = rd(); m = rd();
for(ri i = 1;i <= n;++i){
d[i] = rd();
if(!(~d[i]) && !(~cp)) cp = i;//cp -> changing positon
}
for(ri i = 1,u,v;i <= m;++i)
u = rd(),v = rd(),add(u,v),add(v,u);
dfs(1);//建树
solve(1);//按先保证儿子满足的方式递归处理整棵树
if(~d[1] && du[1] ^ d[1] && (~cp)) change(cp);//需要change并且可以change
if(~d[1] && du[1] ^ d[1]){
puts("-1");
return 0;
}
for(ri i = 2;i <= n;++i)
if(chos[i]) ans[++cnt] = ed[i];
prin(cnt); puts("");
for(ri i = 1;i <= cnt;++i) prin(ans[i]),putchar(‘ ‘);
puts("");
return 0;
}
完结撒花///QwQ///
CF840B Leha and another game about graph
原文:https://www.cnblogs.com/Lumos1921/p/14829477.html