一、题目
不想多说,传送门
二、解法
设为第
i
i
i个点按开关
x
i
xi
xi次,我们把它当做未知数带入邻接矩阵的方程去解,显然有:
(
a
[
1
]
[
i
]
×
x
1
⊕
a
[
2
]
[
i
]
×
x
2
…
…
⊕
a
[
n
]
[
i
]
×
x
n
)
=
1
(a[1][i]\times x1 \oplus a[2][i]\times x2 ……\oplus a[n][i]\times xn)=1
(a[1][i]×x1⊕a[2][i]×x2……⊕a[n][i]×xn)=1
由于开关的性质显然方程是
%
2
\%2
%2意义下的。
保证有解,所以只有两种情况。
1、方程只有一组解,这个解是唯一的,也是最小的。
2、方程有自由元,直接
d
f
s
dfs
dfs每个自由元,枚举后取最小值即可。
#include <cstdio>
#include <iostream>
using namespace std;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,x,y,ans=0x3f3f3f3f,l[105];
int a[105][105];
bool gauss()
{
bool flag=1;
for(int i=1;i<=n;i++)
{
int r=i;
while(r<=n && !a[r][i]) r++;
if(r>n)
{
flag=0;
continue;
}
swap(a[i],a[r]);
for(int j=1;j<=n;j++)
{
if(i==j || !a[j][i]) continue;
for(int k=i+1;k<=n+1;k++)
a[j][k]^=a[i][k];
a[j][i]=0;
}
}
return flag;
}
void dfs(int x,int num)
{
if(num>=ans) return ;
if(x==0) {ans=num;return ;}
if(a[x][x])
{
bool v=a[x][n+1];
for(int i=x+1;i<=n;i++) if(a[x][i]) v^=l[i];
dfs(x-1,num+v);
}
else
{
dfs(x-1,num);
l[x]=1;
dfs(x-1,num+1);
l[x]=0;
}
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++) a[i][i]=a[i][n+1]=1;
for(int i=1;i<=m;i++) x=read(),y=read(),a[x][y]=a[y][x]=1;
if(gauss())
{
ans=0;
for(int i=1;i<=n;i++) ans+=a[i][n+1];
printf("%d\n",ans);
}
else
{
dfs(n,0);
printf("%d\n",ans);
}
}