[BZOJ]1770: [Usaco2009 Nov]lights 燈 高斯消元解xor方程组

Description

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

题解:

经典的开关灯问题,对于第i个方程,如果第j盏灯能影响到第i盏灯,那么第j项前的系数为1,注意自己也能影响到自己,然后最后要全部打开,所以最后的结果都为1,然后是对自由元的处理,若a[i][i]在最后为0,那么表示它填0或1都是能得出解的,然后题目要求最少,天真的我就以为让自由元全部等于0就好了,实际上这是十分SB的。因为它会对其它的答案有影响,所以我们需要用一次dfs,枚举它到底填什么答案会最优。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int Maxn=40;
const int Maxm=600;
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<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
int n,m,ans[Maxn],Ans=100;
bitset<Maxn>a[Maxn];
void gauss()
{
    for(int i=1;i<=n;i++)
    {
        int j;
        for(j=i;j<=n&&!a[j][i];j++);
        if(j>n)continue;
        swap(a[i],a[j]);
        for(int k=i+1;k<=n;k++)
        if(a[k][i])a[k]=a[k]^a[i];
    }
}
void dfs(int x,int cnt)
{
    if(cnt>=Ans)return;
    if(!x){Ans=cnt;return;}
    if(a[x][x])
    {
        int t=a[x][n+1];
        for(int i=x+1;i<=n;i++)t=t^(ans[i]*a[x][i]);
        ans[x]=t;
        dfs(x-1,cnt+t);
    }
    else
    {
        ans[x]=1;dfs(x-1,cnt+1);
        ans[x]=0;dfs(x-1,cnt);
    }
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        a[x][y]=1;a[y][x]=1;
    }
    for(int i=1;i<=n;i++)a[i][n+1]=a[i][i]=1;
    gauss();
    dfs(n,0);
    printf("%d",Ans);
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_36797646/article/details/78188438
个人分类: 高斯消元
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭