题目
贝希和她的闺密们在她们的牛棚中玩游戏。但是天不从人愿,突然,牛棚的电源跳闸了,所有的灯都被关闭了。贝希是一个很胆小的女生,在伸手不见拇指的无尽的黑暗中,她感到惊恐,痛苦与绝望。她希望您能够帮帮她,把所有的灯都给重新开起来!她才能继续快乐地跟她的闺密们继续玩游戏! 牛棚中一共有N(1 <= N <= 35)盏灯,编号为1到N。这些灯被置于一个非常複杂的网络之中。有M(1 <= M <= 595)条很神奇的无向边,每条边连接两盏灯。 每盏灯上面都带有一个开关。当按下某一盏灯的开关的时候,这盏灯本身,还有所有有边连向这盏灯的灯的状态都会被改变。状态改变指的是:当一盏灯是开著的时候,这盏灯被关掉;当一盏灯是关著的时候,这盏灯被打开。 问最少要按下多少个开关,才能把所有的灯都给重新打开。 数据保证至少有一种按开关的方案,使得所有的灯都被重新打开。
分析
和这道题是一样的 树
不过更新了方法,这次不会被卡了,加了优化
code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<vector>
#define ll long long
using namespace std;
int a[1000][1000],b[1000];
int n,m;
int ans;
int l[1000];
void calc(int x,int num)
{
if (num>ans) return;
if (x==0){
ans=num;
return;
}
if (a[x][x])
{
int v=b[x];
for(int i=x+1;i<=n;i++) if(a[x][i]) v^=l[i];
calc(x-1,num+v);
}
else
{
calc(x-1,num);
l[x]=1;
calc(x-1,num+1);
l[x]=0;
}
}
int main()
{
scanf("%d%d",&n,&m);
memset(a,0,sizeof(a));
for (int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
a[x][y]=1; a[y][x]=1;
}
for (int i=1;i<=n;i++)
{b[i]=1;a[i][i]=1;}
for (int i=1;i<=n;i++)
{
int k,c;
for (k=i;k<=n;k++)
if (a[k][i])
break;
if (k==(n+1))
{continue;}
for (int j=1;j<=n;j++)
{
c=a[i][j];
a[i][j]=a[k][j];
a[k][j]=c;
}
c=b[i]; b[i]=b[k]; b[k]=c;
for (int j=1;j<=n;j++)
{
if ((j==i)||(!a[j][i])) continue;
b[j]^=b[i];
for (int l=1;l<=n;l++)
a[j][l]^=a[i][l];
}
}
ans=200000000;
calc(n,0);
printf("%d\n",ans);
}