• BZOJ 2466 [中山市选2009]树(高斯消元)


    【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2466

    【题目大意】

      给定一棵树,每个节点有一盏指示灯和一个按钮。如果节点的按扭被按了,
      那么该节点的灯会从熄灭变为点亮(当按之前是熄灭的),或者从点亮到熄灭
      并且该节点的直接邻居也发生同样的变化。开始的时候,所有的指示灯都是熄灭的。
      请编程计算最少要按多少次按钮,才能让所有节点的指示灯变为点亮状态。

    【题解】

      高斯消元枚举自由变元回代。

    【代码】

    #include <cstdio>
    #include <algorithm>
    #include <cstring> 
    using namespace std;
    namespace Gauss{
        const int N=110,MOD=2,INF=1e9;
        int a[N][N],ans[N];
        bool isFreeX[N];
        int inv(int a,int m){return(a==1?1:inv(m%a,m)*(m-m/a)%m);} 
        int getAns(int n,int m,int r){
            int res=0;
            for(int i=r-1;~i;i--){
                for(int j=0;j<m;j++){
                    if(!a[i][j])continue;
                    ans[j]=a[i][m];
                    for(int k=j+1;k<m;k++){
                        ans[j]-=a[i][k]*ans[k];
                        ans[j]%=MOD;
                        if(ans[j]<0)ans[j]+=MOD;
                    }
                    ans[j]=ans[j]*inv(a[i][j],MOD)%MOD;
                    break;
                }
            }
            for(int i=0;i<m;i++)res+=ans[i];
            return res;
        }
        int gauss(int n,int m){
            for(int i=0;i<m;i++)isFreeX[i]=0;
            int r=0,c=0;
            for(;r<n&&c<m;r++,c++){
                int maxR=r;
                for(int i=r+1;i<n;i++)if(abs(a[i][c])>abs(a[maxR][c]))maxR=i;
                if(maxR!=r)swap(a[maxR],a[r]);
                if(!a[r][c]){r--;isFreeX[c]=1;continue;}
                for(int i=r+1;i<n;i++){
                    if(a[i][c]){
                        int delta=a[i][c]*inv(a[r][c],MOD);
                        for(int j=c;j<=m;j++){
                            a[i][j]-=delta*a[r][j];
                            a[i][j]%=MOD;
                            if(a[i][j]<0)a[i][j]+=MOD;
                        }
                    }
                }
            }
            for(int i=r;i<n;i++)if(a[i][m])return -1;
            return r;
        }
        // 模2枚举自由变元
        int getMinAns(int n,int m,int r){
            int res=INF,freeX=m-r;
            for(int s=0;s<1<<freeX;s++){
                if(__builtin_popcount(s)>=res)continue;
                int cnt=0;
                for(int j=0;j<m;j++){
                    if(isFreeX[j]){
                        ans[j]=s>>cnt&1;
                        ++cnt;
                    }
                }res=min(res,getAns(n,m,r));
            }return res;
        }
    }
    int n,x,y;
    int main(){
        while(~scanf("%d",&n),n){
            using namespace Gauss;
            memset(a,0,sizeof(a));
            for(int i=1;i<n;i++){
                scanf("%d%d",&x,&y);
                a[x-1][y-1]=1;
                a[y-1][x-1]=1;
            }
            for(int i=0;i<n;i++)a[i][i]=a[i][n]=1;
            int r=gauss(n,n);
            printf("%d
    ",getMinAns(n,n,r));
        }return 0;
    }
  • 相关阅读:
    获取docx文件中表格的内容
    从指定地址获取文件进行正则匹配,输出至指定表格
    遍历ID从数据库获得需要的数据
    python实现将txt文件内容存入mysql数据库中
    Dockerfile 文件学习(二)
    Dockerfile 文件学习(二)
    Docker数据卷
    Docker最详细的命令记载
    docker学习
    Vm 热添加<在不重新启动虚拟机,就可以为虚拟机添加硬盘>
  • 原文地址:https://www.cnblogs.com/forever97/p/bzoj2466.html
Copyright © 2020-2023  润新知