POJ3185高斯消元

简介:
The Water Bowls
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 3372   Accepted: 1315

Description

The cows have a line of 20 water bowls from which they drink. The bowls can be either right-side-up (properly oriented to serve refreshing cool water) or upside-down (a position which holds no water). They want all 20 water bowls to be right-side-up and thus use their wide snouts to flip bowls.  

Their snouts, though, are so wide that they flip not only one bowl but also the bowls on either side of that bowl (a total of three or -- in the case of either end bowl -- two bowls).  

Given the initial state of the bowls (1=undrinkable, 0=drinkable -- it even looks like a bowl), what is the minimum number of bowl flips necessary to turn all the bowls right-side-up?

Input

Line 1: A single line with 20 space-separated integers

Output

Line 1: The minimum number of bowl flips necessary to flip all the bowls right-side-up (i.e., to 0). For the inputs given, it will always be possible to find some combination of flips that will manipulate the bowls to 20 0's.

Sample Input

0 0 1 1 1 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0

Sample Output

3

Hint

Explanation of the sample:  

Flip bowls 4, 9, and 11 to make them all drinkable:  
0 0 1 1 1 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0 [initial state]  
0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0 [after flipping bowl 4]  
0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 [after flipping bowl 9]  
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 [after flipping bowl 11]

Source

 
题解:
这题也是联动问题 与POJ1222相似 点击打开链接POJ1222
只是构造增广阵的方式不通 按照高消+DFS模板就可以过
 
#include <iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=230;
int a[maxn][maxn+1],x[maxn];//a 是系数矩阵和增广矩阵,x 是最后存放的解
// a[][maxn]中存放的是方程右面的值(bi)
int equ,var;//equ 是系数阵的行数,var 是系数矩阵的列数(变量的个数)
int free_num,ans=100000000;

int abs1(int num) //取绝对值
{
    if (num>=0) return num;
    else
        return -1*num;
}
void Debug(void)
{
    int i, j;
    for (i = 0; i < equ; i++)
    {
        for (j = 0; j < var + 1; j++)
        {
            cout << a[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}
//调试输出,看消元后的矩阵值,提交时,就不用了
inline int gcd(int a, int b) //最大公约数
{
    int t;
    while (b != 0)
    {
        t = b;
        b = a % b;
        a = t;
    }
    return a;
}

inline int lcm(int a, int b) //最小公倍数
{
    return a * b / gcd(a, b);
}

int dfs(int p) //枚举自由解,只能取0-1,枚举完就回带,找到最小的
{
    if (p<=free_num-1) //深入到了主对角线元素非0 的行了
    {
        //下面就是回带的代码啊
        for(int i = free_num-1; i >= 0; --i)
        {
            int tmp = a[i][var] % 2;
            for(int j = i+1; j < var; ++j) //x[i]取决于x[i+1]--x[var]啊,所以后面的解对前面的解有影
//响。
                if(a[i][j] != 0)
                    tmp = ( tmp - (a[i][j]*x[j])%2 + 2 ) % 2;
            x[i] = (tmp/a[i][i]) % 2; //上面的正常解
        } //回带完成了
//计算解元素为1 的个数;
        int sum=0;
        for(int i=0; i<var; i++) sum+=x[i];
        if (ans>sum) ans=sum;
        return 0;
    }
    x[p]=0;
    dfs(p-1);
    x[p]=1;
    dfs(p-1);
}
void swap(int &a,int &b)
{
    int temp=a;    //交换 2 个数
    a=b;
    b=temp;
}
int Gauss()
{
    int k,col = 0;
//当前处理的列
    for(k = 0; k < equ && col < var; ++k,++col)
    {
        int max_r = k;
        for(int i = k+1; i < equ; ++i)
            if(a[i][col] > a[max_r][col])
                max_r = i;
        if(max_r != k)
        {
            for(int i = k; i < var + 1; ++i)
                swap(a[k][i],a[max_r][i]);
        }
        if(a[k][col] == 0)
        {
            k--;
            continue;
        }
        for(int i = k+1; i < equ; ++i)
        {
            if(a[i][col] != 0)
            {
                int LCM = lcm(a[i][col],a[k][col]);
                int ta = LCM/a[i][col], tb = LCM/a[k][col];
                if(a[i][col]*a[k][col] < 0)
                    tb = -tb;
                for(int j = col; j < var + 1; ++j)
                    a[i][j] = ( (a[i][j]*ta)%2 - (a[k][j]*tb)%2 + 2 ) % 2;
                // 0 和 1 两种状态
            }
        }
    }
//a[i][j]只有

//上述代码是消元的过程,行消元完成
//解下来 2 行,判断是否无解
//注意 K 的值,k 代表系数矩阵值都为 0 的那些行的第 1 行
    for(int i = k; i < equ; ++i)
        if(a[i][col] != 0)
            return -1;
//Debug();

//唯一解或者无穷解,k<=var
//var-k==0 唯一解;var-k>0 无穷多解,自由解的个数=var-k
//能执行到这,说明肯定有解了,无非是 1 个和无穷解的问题。
//下面这几行很重要,保证秩内每行主元非 0,且按对角线顺序排列,就是检查列
    for(int i = 0; i <equ; ++i)//每一行主元素化为非零
        if(!a[i][i])
        {
            int j;
            for(j = i+1; j<var; ++j)
                if(a[i][j])
                    break;
            if(j == var)
                break;
            for(int k = 0; k < equ; ++k)
                swap(a[k][i],a[k][j]);
        }
// ----处理保证对角线主元非 0 且顺序,检查列完成

    free_num=k;
    if (var-k>0)
    {
        dfs(var-1);
        return ans;
        //无穷多解,先枚举解,然后用下面的回带代码进行回带;
//这里省略了下面的回带的代码;不管唯一解和无穷解都可以回带,只不过无穷解
//回带时,默认为最后几个自由变元=0 而已。
    }
    if(var-k<0)
        return -1;
// 无解返回 -1
    if (var-k==0)//唯一解时
    {
//下面是回带求解代码,当无穷多解时,最后几行为 0 的解默认为 0;
        for(int i = k-1; i >= 0; --i) //从消完元矩阵的主对角线非 0 的最后 1 行,开始往
//回带
        {
            int tmp = a[i][var] % 2;

            for(int j = i+1; j < var; ++j) //x[i]取决于 x[i+1]--x[var]啊,所以后面的解对前面的解有影响。
                if(a[i][j] != 0)
                    tmp = ( tmp - (a[i][j]*x[j])%2 + 2 ) % 2;
            //if (a[i][i]==0) x[i]=tmp;//最后的空行时,即无穷解得
            //else
            x[i] = (tmp/a[i][i]) % 2; //上面的正常解
        }
        int sum=0;
        for(int i=0; i<var; i++)
            sum+=x[i];
        return sum;

        //回带结束了
    }
}

int main()
{
    int map[22];
    equ=var=20;
    while(scanf("%d",&map[0])!=EOF)
    {
        for(int i=1; i<20; i++)
            scanf("%d",&map[i]);
        memset(a,0,sizeof(a));
        memset(x,0,sizeof(x));
        for(int i=0; i<20; i++)
        {

            a[i][i]=1;
            if(i>0)
                a[i][i-1]=1;
            if(i<19)
                a[i][i+1]=1;
            if(map[i])
                a[i][20]=1;
        }
        int j1=Gauss();
        printf("%d\n",j1);
    }
    return 0;
}

目录
相关文章
|
9月前
|
XML 人工智能 安全
qq网警加入群聊恶搞代码, QQ卡片XML消息生成工具,装逼娱乐代码生成器
QQ装逼娱乐代码生成器是一款趣味性十足的Python工具,能生成黑客、AI、量子计算、区块链和元宇宙五种风格的专业级代码片段
|
传感器 数据采集 存储
项目实战:嵌入式系统应用开发
项目实战:嵌入式系统应用开发
|
11月前
|
安全 API 数据安全/隐私保护
12种API认证全场景解析:从Basic到OAuth2.0,哪个认证最适合你的业务?
在API认证领域,从简单的Key-Value到高级的OAuth2.0和JWT,共有12种主流认证方式。本文详解了每种方式的意义、适用场景及优劣,并通过认证方式矩阵对比常见工具(如Postman、Apifox)的支持情况。此外,还介绍了企业级安全功能,如密钥保险箱、动态令牌和合规审计。选择合适的认证方式不仅能提升安全性,还能大幅提高开发效率。未来,自动化认证矩阵或将成为API调试的核心趋势。
|
应用服务中间件 网络安全 nginx
轻松上手Nginx Proxy Manager:安装、配置与实战
Nginx Proxy Manager (NPM) 是一款基于 Nginx 的反向代理管理工具,提供直观的 Web 界面,方便用户配置和管理反向代理、SSL 证书等。本文档介绍了 NPM 的安装步骤,包括 Docker 和 Docker Compose 的安装、Docker Compose 文件的创建与配置、启动服务、访问 Web 管理界面、基本使用方法以及如何申请和配置 SSL 证书,帮助用户快速上手 NPM。
12614 1
|
TensorFlow 算法框架/工具
基于Tensorflow实现Transformer模型
基于Tensorflow实现Transformer模型
760 0
|
Ubuntu TensorFlow 算法框架/工具
最新 Tensorflow 2.2极简安装教程 | 学习笔记
快速学习最新 Tensorflow 2.2极简安装教程
最新 Tensorflow 2.2极简安装教程 | 学习笔记
|
测试技术
Spring-AOP @AspectJ进阶之绑定抛出的异常
Spring-AOP @AspectJ进阶之绑定抛出的异常
196 0
|
算法
【每日算法】AB6 表达式求值(基于逆波兰表达式)
【每日算法】AB6 表达式求值(基于逆波兰表达式)
201 0
|
存储 数据采集 缓存
缓存,确实很香,却也很受伤!
缓存,确实很香,却也很受伤!
220 0
缓存,确实很香,却也很受伤!
|
Python
Python读取excel中的图片
Python读取excel中的图片
2575 0

热门文章

最新文章