zoukankan      html  css  js  c++  java
  • POJ 2345 Central heating(高斯消元)


    【题目链接】 http://poj.org/problem?id=2345

    【题目大意】

      给出n个开关和n个人,每个人可以控制一些开关,现在所有的开关都是关着的
      一个指令可以让一个人掰动所有属于他控制的开关,使得开关的状态变化,
      现在要求求出最少的指令,使得开关全开,按字典序输出指令的人

    【题解】

      我们将人的操作作为变元建立方程组,因为一个人相同的两次操作对结果是没有影响的
      我们可以认为这是无效操作,所以每个人操作的次数只是一次或者零次,
      我们解01方程组即可得到答案。

    【代码】

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    //对2取模的01方程组
    const int MAXN=300;
    //有equ个方程,var个变元。增广矩阵行数为equ,列数为var+1,分别为0到var
    int equ,var;
    int a[MAXN][MAXN]; //增广矩阵
    int x[MAXN]; //解集
    int free_x[MAXN];//用来存储自由变元(多解枚举自由变元可以使用)
    int free_num;//自由变元的个数
    //返回值为-1表示无解,为0是唯一解,否则返回自由变元个数
    int Gauss(){
        int max_r,col,k;
        free_num = 0;
        for(k=0,col=0;k<equ&&col<var;k++,col++){
            max_r=k;
            for(int i=k+1;i<equ;i++){
                if(abs(a[i][col])>abs(a[max_r][col]))max_r=i;
            }
            if(a[max_r][col] == 0){
                k--;
                free_x[free_num++]=col;//这个是自由变元 
                continue;
            }
            if(max_r != k){
                for(int j=col;j<var+1;j++)swap(a[k][j],a[max_r][j]);
            }
            for(int i=k+1;i<equ;i++){
                if(a[i][col]!=0){
                    for(int j=col;j<var+1;j++)a[i][j]^=a[k][j];
                }
            }
        }
        for(int i=k;i<equ;i++)if(a[i][col]!=0)return -1;//无解
        if(k<var)return var-k;//自由变元个数
        //唯一解,回代
        for(int i=var-1;i>=0;i--){
            x[i]=a[i][var];
            for(int j=i+1;j<var;j++)x[i]^=(a[i][j]&&x[j]);
        }return 0;
    }
    int n;
    int main(){
        while(~scanf("%d",&n)){
            memset(a,0,sizeof(a));
            for(int i=0;i<n;i++){
                int t;
                while(scanf("%d",&t),t!=-1){
                    a[t-1][i]=1;
                }
            }for(int i=0;i<n;i++)a[i][n]=1;
            equ=n,var=n;
    		Gauss();
            int flag=0;
            for(int i=0;i<n;i++){
                if(x[i]){
                    if(flag++)printf(" %d",i+1);
                    else printf("%d",i+1);
                }
            }puts("");
        }return 0;
    }
  • 相关阅读:
    DEDE后台登录提示成功但是一下子就弹出重新登录
    商务通对话窗口左侧图片广告
    html文档类型能直接改成html5吗?
    <meta http-equiv="pragma" content="no-cache"/>是什么意思?
    <meta name="location" content="province=湖北;city=襄阳;coord=112.167975,32.047654">
    取消百度转码<head></head>
    <base target=_blank>
    把数据保存到数据库主表 `#@__archives` 时出错
    DEDECMS后台文章编辑内容框消失解决方法
    【转】vs 常用快捷键
  • 原文地址:https://www.cnblogs.com/forever97/p/poj2345.html
Copyright © 2011-2022 走看看