我们要使左边的点度数都变为偶数。考虑第一种操作,会使左边两个点的度奇偶性变化,所以问题就转化成:给出一个图,选较少的边使得每个点的度满足奇偶性的限制。
这个怎么搞呢?有一个结论:若有解,则图的任意一个生成树,只取树边中的一些边都能得到一组解。
怎么证明呢?
显然如果已知一组边是合法的解,那么这些边一定能在同一棵生成树上。
把这组解的边标为白色边。对于其他的任意一颗生成树,若白边在树上就取他,若白边不在树上,就取对应的环。(这里取相同边次数是异或的)。这样一定能构造出在这个树上的合法解。证毕。
所以随便dfs出一颗生成树从叶往根取就好了。最多选 n−1 条。
对与右边,把奇点两两配对就好了。最多 n/2 。
还要花 n−1 保证图联通。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=300005,maxe=600005;
int n,m,dL[maxn],dR[maxn],res1[maxn],res2[maxn];
int fir[maxn],nxt[maxe],son[maxe],id[maxe],tot;
bool vis[maxn];
struct data{ int x,y; } a[maxn];
void add(int x,int y,int z){
son[++tot]=y; id[tot]=z; nxt[tot]=fir[x]; fir[x]=tot;
}
void dfs(int x,int pre,int e_id){
vis[x]=true;
for(int j=fir[x];j;j=nxt[j]) if(!vis[son[j]]) dfs(son[j],x,id[j]);
if(dL[x]&1){
res1[++res1[0]]=e_id;
dL[x]++, dL[pre]++;
dR[a[e_id].x]++; dR[a[e_id].y]--;
}
}
int main(){
freopen("hhhoj22.in","r",stdin);
freopen("hhhoj22.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&a[i].x,&a[i].y), dL[a[i].x]++, dR[a[i].y]++;
add(a[i].x,a[i].y,i), add(a[i].y,a[i].x,i);
}
for(int i=1;i<=n;i++) if(!vis[i]){
dfs(i,0,0);
if(dL[0]) return printf("-1\n"),0;
}
dR[1]++; dR[n]++;
for(int i=1;i<=n;i++) if(dR[i]&1) res2[++res2[0]]=i;
if(res2[0]&1) return printf("-1\n"),0;
printf("%d\n",res1[0]+res2[0]/2+n-1);
for(int i=1;i<=res1[0];i++) printf("1 %d %d\n",a[res1[i]].x,a[res1[i]].y);
for(int i=1;i<=res2[0]-1;i+=2) printf("2 %d %d\n",res2[i],res2[i+1]);
for(int i=1;i<=n-1;i++) printf("2 %d %d\n",i,i+1);
return 0;
}