[BZOJ1770/Luogu2962][Usaco2009 Nov]lights 燈(高斯消元,搜索)

发布于 2018-03-27  56 次阅读


本文章由SYCstudio或本站其它作者所有,请勿擅自转载

本文链接地址:[BZOJ1770/Luogu2962][Usaco2009 Nov]lights 燈(高斯消元,搜索)

Description

貝希和她的閨密們在她們的牛棚中玩遊戲。但是天不從人願,突然,牛棚的電源跳閘了,所有的燈都被關閉了。貝希是一個很膽小的女生,在伸手不見拇指的無盡的黑暗中,她感到驚恐,痛苦與絕望。她希望您能夠幫幫她,把所有的燈都給重新開起來!她才能繼續快樂地跟她的閨密們繼續玩遊戲! 牛棚中一共有N(1 <= N <= 35)盞燈,編號為1到N。這些燈被置於一個非常複雜的網絡之中。有M(1 <= M <= 595)條很神奇的無向邊,每條邊連接兩盞燈。 每盞燈上面都帶有一個開關。當按下某一盞燈的開關的時候,這盞燈本身,還有所有有邊連向這盞燈的燈的狀態都會被改變。狀態改變指的是:當一盞燈是開著的時候,這盞燈被關掉;當一盞燈是關著的時候,這盞燈被打開。 問最少要按下多少個開關,才能把所有的燈都給重新打開。 數據保證至少有一種按開關的方案,使得所有的燈都被重新打開。

Tag

高斯消元,搜索

解决思路

首先对于每一个点操作两次以上是没有意义的,每一个点最多只会操作一次。那么设F[i]表示i有没有被操作,能够列出异或方程
\[F[i]\wedge F[v1]\wedge F[v2]……=1 \quad (v \quad linked\quad i)\]
高斯消元解出这个方程后,可以得到一个上三角矩阵、若干有确定解的元和若干自由元。
那么枚举这些自由元是开灯还是不开灯。相应的,能够根据高斯消元消出的上三角矩阵解出所有的灯的操作情况,从它们中取最优值。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<bitset>
using namespace std;

#define ll long long
#define mem(Arr,x) memset(Arr,x,sizeof(Arr))

const int maxN=40;
const int inf=2147483647;

int n,m;
int Ans=inf,Status[maxN];
bitset<maxN> A[maxN];

void Gauss();
void dfs(int now,int tot);

int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for (int i=1;i<=m;i++)
    {
        int u,v;cin>>u>>v;
        A[u][v]=A[v][u]=1;
    }
    for (int i=1;i<=n;i++) A[i][n+1]=A[i][i]=1;
    Gauss();//高斯消元
    dfs(n,0);//枚举自由元选择然后求解
    cout<<Ans<<endl;
    return 0;
}

void Gauss()//高斯消元
{
    int now=0;
    for (int i=1;i<=n;i++)
    {
        now++;int j=now;
        while ((A[j][i]==0)&&(j<=n)) j++;
        if (j>n) continue;//如果发现是自由元,直接continue
        if (now!=j) swap(A[now],A[j]);
        for (int k=1;k<=n;k++)
            if ((k!=now)&&(A[k][i]==1)) A[k]^=A[now];
    }
    return;
}

void dfs(int now,int tot)
{
    if (tot>=Ans) return;//最优性剪枝
    if (now==0)
    {
        Ans=min(Ans,tot);
        return;
    }
    if (A[now][now]==1)//高斯消元时不是自由元,那么由上三角和后面得到的每一个变量的取值可以推出这一次的取值
    {
        int t=A[now][n+1];
        for (int i=now+1;i<=n;i++) if (A[now][i]) t^=Status[i];
        Status[now]=t;
        dfs(now-1,tot+t);
    }
    else//是自由元,那就有两种取值,分别向下计算
    {
        Status[now]=0;dfs(now-1,tot);
        Status[now]=1;dfs(now-1,tot+1);
    }
    return;
}

本文章由SYCstudio或本站其它作者所有,请勿擅自转载

本文链接地址:[BZOJ1770/Luogu2962][Usaco2009 Nov]lights 燈(高斯消元,搜索)


HNCJ OIer