BZOJ 1770 lights燈

余生长醉 提交于 2019-12-13 18:18:07

题目传送门

分析:

跑着去学了一波异或方程组高斯消元

(全世界就我不知道系列。。)

然后我们可以列方程组诶

(a[1][x]&x[1])^(a[2][x]&x[2])^...^(a[n][x]&x[n])=b[x]

a[i][x]表示i号开关是否与x号灯相连,x[i]即为此开关开不开,b[x]为灯泡末状态,此题均为1

然后就会成为一个行列式

由于a[i][j]的值为0或1

所以消元时直接行与行异或就好了,不会影响结果

然后会解出一个上三角

但是a[i][i]可能会等于0,表示这个位置填0和1都有解

于是这种地方可以直接爆搜出答案

dfs的过程就是高斯消元最后取ans的过程了。。。

讲不清楚看代码2333

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>

#define maxn 55
#define INF 0x3f3f3f3f
#define MOD 1000000007

using namespace std;

inline int getint()
{
    int num=0,flag=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    return num*flag;
}

int n,m;
int a[maxn][maxn];
int ans[maxn],Ans=INF;

inline void Gauss()
{
    for(int i=1;i<=n;i++)
    {
        int id=i;
        while(id<=n&&!a[id][i])id++;
        if(id!=i)for(int j=1;j<=n+1;j++)swap(a[i][j],a[id][j]);
        for(int j=i+1;j<=n;j++)if(a[j][i])
            for(int k=1;k<=n+1;k++)a[j][k]^=a[i][k];
    }
}

inline void dfs(int x,int num)
{
    if(num>Ans)return;
    if(!x){Ans=num;return;}
    if(a[x][x])
    {
        int tmp=a[x][n+1];
        for(int i=x+1;i<=n;i++)if(a[x][i])tmp^=ans[i];
        ans[x]=tmp;
        dfs(x-1,num+tmp);
    }
    else
    {
        dfs(x-1,num),ans[x]=1,dfs(x-1,num+1),ans[x]=0;
    }
}

int main()
{
    n=getint(),m=getint();
    for(int i=1;i<=n;i++)a[i][i]=a[i][n+1]=1;
    for(int i=1;i<=m;i++)
    {
        int u=getint(),v=getint();
        a[u][v]=a[v][u]=1;
    }
    Gauss();
    dfs(n,0);
    printf("%d\n",Ans);
}
View Code

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!