[Usaco2009 Nov]lights

题目描述:

给出$n$,$m$,表示有$n$盏灯和$m$条奇怪的电线,按下电线一段的灯后另一端会有影响。

求最少按几次。

题解:

高消解异或方程组,得到一堆自由元后搜索自由元状态,然后不断更新答案。

数据卡贪心好评。

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 40;
int n,m,hed[N],cnt;
struct EG
{
    int to,nxt;
}e[N*N];
void ae(int f,int t)
{
    e[++cnt].to = t;
    e[cnt].nxt = hed[f];
    hed[f] = cnt;
}
int a[N][N];
int fre[N],tl;
void gs()
{
    int l1;
    for(l1=1;l1<=n;l1++)
    {
        int tmp = l1;
        while(tmp<=n&&!a[tmp][l1])tmp++;
        if(tmp>n)continue;
        if(tmp!=l1)for(int i=l1;i<=n+1;i++)swap(a[l1][i],a[tmp][i]);
        for(int i=1;i<=n;i++)
            if(a[i][l1]&&i!=l1)
                for(int j=l1;j<=n+1;j++)a[i][j]^=a[l1][j];
    }
}
int ans=0x3f3f3f3f;
void dfs(int dep,int now)
{
    if(now>=ans)return ;
    if(!dep){ans=now;return ;}
    if(a[dep][dep])
    {
        dfs(dep-1,now+a[dep][n+1]);
    }else
    {
        if(a[dep][n+1])return ;
        dfs(dep-1,now);
        for(int j=dep-1;j>=1;j--)a[j][n+1]^=a[j][dep];
        dfs(dep-1,now+1);
        for(int j=dep-1;j>=1;j--)a[j][n+1]^=a[j][dep];
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int f,t,i=1;i<=m;i++)
    {
        scanf("%d%d",&f,&t);
        ae(f,t),ae(t,f);
    }
    for(int i=1;i<=n;i++)
    {
        a[i][i]=a[i][n+1]=1;
        for(int j=hed[i];j;j=e[j].nxt)
        {
            int to = e[j].to;
            a[i][to]^=1;
        }
    }
    gs();
    dfs(n,0);
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2019-03-04 23:12  LiGuanlin  阅读(162)  评论(1编辑  收藏  举报