[USACO09NOV]灯Lights

一、题目

不想多说,传送门

二、解法

设为第 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]×x1a[2][i]×x2a[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);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值