zoukankan      html  css  js  c++  java
  • luogu2962 [USACO09NOV]灯Lights

    题目链接:luogu2962

    这个题还可以折半搜索(似乎复杂度更有保证),不过作为练手更适合写异或方程组的高斯消元

    异或方程组的高斯消元一般是如下形式

    [(a_{i,1}*x_1) ext^(a_{i,2}*x_2) ext^cdots ext^(a_{i,n}*x_n)=y_n ]

    ( ext^)表示异或运算符,所有的数均(in[0,1])

    注意到异或操作类似于加减操作,直接对两个式子进行异或操作的话可以约去一些项

    于是可以类似于高斯消元的方式对该方程进行求解

    在这题中,(a_{i,j})表示(i,j)之间是否有边相连,(x_i)表示是否打开灯的开关,(y_n)表示所有灯的最终状态,此题中均为(1)

    直接进行高斯消元

    但是会有一个问题:出现了自由元(即无穷解)

    这时候异或方程组的性质就出现了——变量取值均在(0,1)这两个值之间

    我们可以爆搜所有自由元的取值,剩下的用高斯消元得到的式子处理,但是复杂度貌似比较诡异(反正能过)

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<math.h>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    using namespace std;
    #define lowbit(x) (x)&(-x)
    #define sqr(x) (x)*(x)
    #define fir first
    #define sec second
    #define rep(i,a,b) for (register int i=a;i<=b;i++)
    #define per(i,a,b) for (register int i=a;i>=b;i--)
    #define maxd 1000000007
    #define eps 1e-6
    typedef long long ll;
    const int N=100000;
    const double pi=acos(-1.0);
    int n,m,a[110][110],x[110],ans=maxd;
    
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    	while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    	return x*f;
    }
    
    void gauss()
    {
    	rep(i,1,n)
    	{
    		int now=i;
    		while ((now<=n) && (a[now][i]==0)) now++;
    		if (now>n) continue;
    		if (now!=i) swap(a[now],a[i]);
    		rep(j,1,n)
    		{
    			if (i==j) continue;
    			if (a[j][i])
    				rep(k,1,n+1) a[j][k]^=a[i][k];
    		}
    	}
    }
    
    void dfs(int now,int tot)
    {
    	if (tot>=ans) return;
    	if (now==0) {ans=tot;return;}
    	if (a[now][now])
    	{
    		int tmp=a[now][n+1];
    		rep(i,now+1,n) if (a[now][i]) tmp^=x[i];
    		x[now]=tmp;
    		dfs(now-1,tot+=(tmp==1));
    	}
    	else 
    	{
    		x[now]=1;dfs(now-1,tot+1);
    		x[now]=0;dfs(now-1,tot);
    	}
    }
    
    int main()
    {
    	n=read();m=read();
    	rep(i,1,n) {a[i][i]=1;a[i][n+1]=1;}
    	rep(i,1,m)
    	{
    		int u=read(),v=read();
    		a[u][v]=1;a[v][u]=1;
    	}
    	gauss();
    	dfs(n,0);
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    [LUPA学习向导]如何成为Linux平台C语言程序员
    C程序调用shell脚本共有三种方法
    用C语言编写一个Linux下的简单shell程序
    利用sscanf()匹配字符串需要注意贪婪匹配
    对于初学者来说,选择合适的开发板非常之非常重要呀
    迅为IMX6ULL开发板C程序调用shell
    迅为-iMX6ULL开发板上配置AP热点
    迅为iMX6开发板-设备树内核-menuconfig的使用
    双11买它阿,零基础配套视频教程4412开发板嵌入式入门
    迅为-iMX6ULL开发板-移植mjpg-streamer实现远程监控
  • 原文地址:https://www.cnblogs.com/encodetalker/p/10807187.html
Copyright © 2011-2022 走看看