Lights G

Lights G ⁡ \operatorname{Lights\ G} Lights G

Title link: luogu P2962 ⁡ \operatorname{luogu\ P2962}l u o g u P 2 9 6 2 

topic

Give a nnn pointsmmUndirected graph with m edges, the initial state of each point is0 00

You can operate any point, the state of all adjacent endpoints will change after the operation is over, from 0 00 becomes1 11 or1 11 becomes0 00

You need to ask for the minimum number of operations so that all nn after all operations are completedThe state of n points is1 11

enter

Two integers n, mn, m in the first linen,m

After mmm rows, two integersa, ba, b ineach rowa,b , which means that at pointsa, ba, ba,There is an edge between b .

Output

One integer per line indicates the minimum number of operations required.

Sample input

5 6 
1 2 
1 3 
4 2 
3 4 
2 5 
5 3 

Sample output

3 

data range

For 100% 100\%1 0 0 %的 数据 ,1 ≤ n ≤ 35, 1 ≤ m ≤ 595, 1 ≤ a, b ≤ n 1 \ le n \ le35,1 \ le m \ le595, 1 \ le a, b \ le n1n35,1m595,1a,bn

Ideas

This question is a Gaussian elimination question, but an XOR.
(Half-template problem, that is, Gaussian elimination of XOR)

Obviously, each point must be pressed once or not.
The equation is based on whether a point has an effect on other points (or whether each point has an effect on it), then the formula is very simple, just preprocess it.

Then we get the Gaussian elimination of XOR.
Then if there is no free element, we can directly count the answer.
But if there is a free element, it is necessary to enumerate the two states of each free element, and then the part that is not the free element can be directly calculated, and then find the method that requires the least number of presses.

Then there is the answer.

Code

#include<cstdio>
#include<algorithm>

using namespace std;

int n, m, x, y, ans, yes[37][37], choi[37];
bool have;

void gaosi() {
    
    //高斯化简异或式
	have = 1;
	for (int i = 1; i <= n; i++) {
    
    
		int cho = i;
		while (cho <= n && !yes[cho][i]) cho++;
		if (cho == n + 1) {
    
    
			have = 0;
			continue;
		}
		swap(yes[i], yes[cho]);
		for (int j = 1; j <= n; j++)
			if (i != j && yes[j][i]) {
    
    
				for (int k = i + 1; k <= n + 1; k++)
					yes[j][k] ^= yes[i][k];
				yes[j][i] = 0;
			}
	}
}

void dfs(int now, int num) {
    
    //dfs枚举自由元的每一种方式
	if (num >= ans) return ;
	if (!now) {
    
    
		ans = num;
		return ;
	}
	if (yes[now][now]) {
    
    //不是自由元,固定方式
		int add = 0;
		for (int i = now + 1; i <= n; i++)
			if (yes[now][i])
				add ^= choi[i];
		add ^= yes[now][n + 1];
		dfs(now - 1, num + add);
	}
	else {
    
    //是自由元,两个都dfs一次
		dfs(now - 1, num);
		choi[now] = 1;
		dfs(now - 1, num + 1);
		choi[now] = 0;
	}
}

int main() {
    
    
	scanf("%d %d", &n, &m);//读入
	for (int i = 1; i <= n; i++) {
    
    //初始化
		yes[i][i] = 1;
		yes[i][n + 1] = 1;
	}
	for (int i = 1; i <= m; i++) {
    
    
		scanf("%d %d", &x, &y);//读入
		yes[x][y] = 1;//记录
		yes[y][x] = 1;
	}
	
	gaosi();//高斯消元
	if (have) {
    
    //没有自由元
		for (int i = 1; i <= n; i++)
			ans += yes[i][n + 1];//直接找到答案
	}
	else {
    
    //有自由元
		ans = 10000;
		dfs(n, 0);//dfs枚举
	}
	
	printf("%d", ans);//输出
	
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43346722/article/details/108303894