POJ 1681 Painter's Problem (高斯消元 枚举自由变元求最小的步数)
题意:
一个n*n 的木板 ,每个格子 都 可以 染成 白色和黄色,( 一旦我们对也个格子染色 ,他的上下左右 都将改变颜色);
给定一个初始状态 , 求将 所有的 格子 染成黄色 最少需要染几次? 若 不能 染成 输出 inf。
分析:
和1222差不多,唯一的区别是这个题还要求 最短的步数,其实只需要枚举一下最后的x[][]是否为1,即是否需要按下,
由于只有无解或者解唯一,因为按的顺序是没有影响的,所以只要是有解一定唯一,而且最短的情况是每个格子只按一次,
因为按两次以后就变为原来的状态了。
这个是最严谨的这个题的AC代码,因为我做1753的时候用原来的方法错了,看了Kuangbin的博客,知道原来的方法不对,貌似只有一个解和无解的时候才会对。
但是这个是对的:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define LL __int64
const int maxn = +;
const int INF = <<;
using namespace std;
int equ, var, fn;
int a[maxn][maxn], x[maxn];
int free_x[maxn];
int gcd(int a, int b)
{
return b==?a:gcd(b, a%b);
}
int lcm(int a, int b)
{
return a*b/gcd(a, b);
}
int Gauss()
{
int x_mo;
x_mo = ;
int i, j, k, max_r, col;
int ta, tb, LCM, fx_num = ;
col = ; for(k = ; k<equ && col<var; k++, col++)
{
max_r = k;
for(i = k+; i < equ; i++)
if(abs(a[i][col])>abs(a[max_r][col]))
max_r = i; if(max_r != k)
for(j = k; j < var+; j++)
swap(a[k][j], a[max_r][j]); if(a[k][col]==)
{
free_x[fx_num++] = col; //求自由变元所在的列
k--;
continue;
}
for(i = k+; i < equ; i++)
{
if(a[i][col] != )
{
LCM = lcm(abs(a[i][col]), abs(a[k][col]));
ta = LCM/abs(a[i][col]);
tb= LCM/abs(a[k][col]);
if(a[i][col]*a[k][col] < ) tb = -tb; for(j = col; j < var+; j++)
a[i][j] = ((a[i][j]*ta - a[k][j]*tb)%x_mo+x_mo)%x_mo;
}
}
}
for(i = k; i < equ; i++)
if(a[i][col] != )
return -; //以下为模2情况下的,枚举变元的方法。
int stat=<<(var-k);//自由变元有 var-k 个
int res=INF;
for(i=;i<stat;i++)//枚举所有变元
{
int cnt=;
int index=i;
for(j=;j<var-k;j++)
{
x[free_x[j]]=(index&);
if(x[free_x[j]]) cnt++;
index>>=;
}
for(j=k-;j>=;j--)
{
int tmp=a[j][var];
for(int l=j+;l<var;l++)
if(a[j][l]) tmp^=x[l];
x[j]=tmp;
if(x[j])cnt++;
}
if(cnt<res)res=cnt;
}
return res;
} int main()
{
int t, i, j, n, tmp;
char s[maxn];
scanf("%d", &t);
while(t--)
{
memset(a, , sizeof(a));
memset(x, , sizeof(x));
scanf("%d", &n);
equ = n*n;
var = n*n;
for(i = ; i < n; i++)
{
getchar();
scanf("%s", s);
for(j = ; j < n; j++)
{
if(s[j]=='y') a[i*n+j][n*n] = ; //y时为0
else a[i*n+j][n*n] = ;
}
}
for(i = ; i < n; i++)
for(j = ; j < n; j++)
{
tmp = i*n+j;
a[tmp][tmp] = ;
if(j<=n-)
a[tmp+][tmp] = ;
if(j>=)
a[tmp-][tmp] = ;
if(tmp+n<n*n)
a[tmp+n][tmp] = ;
if(tmp-n>=)
a[tmp-n][tmp] = ;
}
fn = Gauss();
if(fn==-)
printf("inf\n");
else
printf("%d\n", fn);
}
return ;
}
这个AC代码是我按照模板改的,但是在多解的情况下不对:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define LL __int64
const int maxn = +;
using namespace std;
int equ, var, fn;
int a[maxn][maxn], x[maxn];
int gcd(int a, int b)
{
return b==?a:gcd(b, a%b);
}
int lcm(int a, int b)
{
return a*b/gcd(a, b);
}
int Gauss()
{
int x_mo;
x_mo = ;
int i, j, k, max_r, col;
int ta, tb, LCM, tmp;
col = ; for(k = ; k<equ && col<var; k++, col++)
{
max_r = k;
for(i = k+; i < equ; i++)
if(abs(a[i][col])>abs(a[max_r][col]))
max_r = i; if(max_r != k)
for(j = k; j < var+; j++)
swap(a[k][j], a[max_r][j]); if(a[k][col]==)
{
k--;
continue;
}
for(i = k+; i < equ; i++)
{
if(a[i][col] != )
{
LCM = lcm(abs(a[i][col]), abs(a[k][col]));
ta = LCM/abs(a[i][col]);
tb= LCM/abs(a[k][col]);
if(a[i][col]*a[k][col] < ) tb = -tb; for(j = col; j < var+; j++)
a[i][j] = ((a[i][j]*ta - a[k][j]*tb)%x_mo+x_mo)%x_mo;
}
}
}
for(i = k; i < equ; i++)
if(a[i][col] != )
return -; for(i = var-; i >= ; i--)
{
tmp = a[i][var];
for(j = i+; j < var; j++)
if(a[i][j] != )
tmp = ((tmp-a[i][j]*x[j])%x_mo+x_mo)%x_mo;
if(a[i][i]==) //注意这a[i][i]可能为0, 我改为这样就对了。
x[i] = ;
else
{
while(tmp%a[i][i]!=) tmp += x_mo;
x[i] = (tmp/a[i][i])%x_mo;
}
}
return ;
} int main()
{
int t, i, j, n, ans, tmp;
char s[maxn];
scanf("%d", &t);
while(t--)
{
memset(a, , sizeof(a));
memset(x, , sizeof(x));
scanf("%d", &n);
equ = n*n;
var = n*n;
for(i = ; i < n; i++)
{
getchar();
scanf("%s", s);
for(j = ; j < n; j++)
{
if(s[j]=='y') a[i*n+j][n*n] = ; //y时为0
else a[i*n+j][n*n] = ;
}
}
for(i = ; i < n; i++)
for(j = ; j < n; j++)
{
tmp = i*n+j;
a[tmp][tmp] = ;
if(j<=n-)
a[tmp+][tmp] = ;
if(j>=)
a[tmp-][tmp] = ;
if(tmp+n<n*n)
a[tmp+n][tmp] = ;
if(tmp-n>=)
a[tmp-n][tmp] = ;
}
fn = Gauss();
if(fn==-)
printf("inf\n");
else
{
ans = ;
for(i = ; i < n*n; i++)
if(x[i]==) //枚举解为1,就是需要将原来的翻转的。
ans ++;
printf("%d\n", ans);
}
}
return ;
}
这个AC代码的模板用的是别人的对二取模的模板,用的是 ^异或,不会出现除0的情况。在多解的情况下也不对。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define LL __int64
const int maxn = +;
using namespace std;
int equ, var, fn;
int a[maxn][maxn], x[maxn];
int gcd(int a, int b)
{
return b==?a:gcd(b, a%b);
}
int lcm(int a, int b)
{
return a*b/gcd(a, b);
}
int Gauss()
{
int i,j,k;
int max_r;
int col;
int temp; int free_x_num;
int free_index; col=;
for(k=;k<equ&&col<var;k++,col++)
{
max_r=k;
for(i=k+;i<equ;i++)
{
if(abs(a[i][col])>abs(a[max_r][col]))max_r=i;
}
if(max_r!=k)
{
for(j=col;j<var+;j++)swap(a[k][j],a[max_r][j]);
}
if(a[k][col]==)
{
k--;
continue;
}
for(i=k+;i<equ;i++)
{
if(a[i][col]!=)
{
for(j=col;j<var+;j++)
a[i][j]^=a[k][j];
}
}
}
for(i=k;i<equ;i++)
{
if(a[i][col]!=)return -;
}
for(i=var-;i>=;i--)
{
x[i]=a[i][var];
for(j=i+;j<var;j++)
x[i]^=(a[i][j]&&x[j]);
}
return ;
} int main()
{
int t, i, j, n, ans, tmp;
char s[maxn];
scanf("%d", &t);
while(t--)
{
memset(a, , sizeof(a));
memset(x, , sizeof(x));
scanf("%d", &n);
equ = n*n;
var = n*n;
for(i = ; i < n; i++)
{
getchar();
scanf("%s", s);
for(j = ; j < n; j++)
{
if(s[j]=='y') a[i*n+j][n*n] = ;
else a[i*n+j][n*n] = ;
}
}
for(i = ; i < n; i++)
for(j = ; j < n; j++)
{
tmp = i*n+j;
a[tmp][tmp] = ;
if(j<=n-)
a[tmp+][tmp] = ;
if(j>=)
a[tmp-][tmp] = ;
if(tmp+n<n*n)
a[tmp+n][tmp] = ;
if(tmp-n>=)
a[tmp-n][tmp] = ;
}
fn = Gauss();
if(fn==-)
printf("inf\n");
else
{
ans = ;
for(i = ; i < n*n; i++)
if(x[i]==)
ans ++;
printf("%d\n", ans);
}
}
return ;
}
POJ 1681 Painter's Problem (高斯消元 枚举自由变元求最小的步数)的更多相关文章
- POJ 1753 Flip Game (高斯消元 枚举自由变元求最小步数)
题目链接 题意:4*4的黑白棋,求把棋全变白或者全变黑的最小步数. 分析:以前用状态压缩做过. 和上题差不多,唯一的不同是这个终态是黑棋或者白棋, 但是只需要把给的初态做不同的两次处理就行了. 感觉现 ...
- POJ 1681 Painter's Problem (高斯消元)
题目链接 题意:有一面墙每个格子有黄白两种颜色,刷墙每次刷一格会将上下左右中五个格子变色,求最少的刷方法使得所有的格子都变成yellow. 题解:通过打表我们可以得知4*4的一共有4个自由变元,那么我 ...
- POJ 1681 Painter's Problem [高斯消元XOR]
同上题 需要判断无解 需要求最小按几次,正确做法是枚举自由元的所有取值来遍历变量的所有取值取合法的最小值,然而听说数据太弱自由元全0就可以就水过去吧.... #include <iostream ...
- POJ 1681 Painter's Problem(高斯消元+枚举自由变元)
http://poj.org/problem?id=1681 题意:有一块只有黄白颜色的n*n的板子,每次刷一块格子时,上下左右都会改变颜色,求最少刷几次可以使得全部变成黄色. 思路: 这道题目也就是 ...
- POJ 1681 高斯消元 枚举自由变元
题目和poj1222差不多,但是解法有一定区别,1222只要求出任意一解,而本题需要求出最少翻转次数.所以需要枚举自由变元,变元数量为n,则枚举的次数为1<<n次 #include < ...
- poj 3185 The Water Bowls 高斯消元枚举变元
题目链接 给一行0 1 的数, 翻转一个就会使他以及它左右两边的都变, 求最少多少次可以变成全0. 模板题. #include <iostream> #include <vector ...
- POJ 1681 Painter's Problem 【高斯消元 二进制枚举】
任意门:http://poj.org/problem?id=1681 Painter's Problem Time Limit: 1000MS Memory Limit: 10000K Total ...
- poj 1681 Painter's Problem(高斯消元)
id=1681">http://poj.org/problem? id=1681 求最少经过的步数使得输入的矩阵全变为y. 思路:高斯消元求出自由变元.然后枚举自由变元,求出最优值. ...
- poj 1681 Painter's Problem
Painter's Problem 题意:给一个n*n(1 <= n <= 15)具有初始颜色(颜色只有yellow&white两种,即01矩阵)的square染色,每次对一个方格 ...
随机推荐
- BLOB或TEXT字段使用散列值和前缀索引优化提高查询速度
1.创建表,存储引擎为myisam,对大文本字段blob使用MD5函数建立一个散列值 create table t2(id varchar(60), content blob, hash_value ...
- 关于 iOS10 更新后 360 云盘 的上传按钮消失的解决方案
最近出了iOS10,作为iOS开发者,果断更新. 但是更新完后,打开自己的360云盘,发现想向云盘上传东西,但是传不了,加号按钮不见了. 经过我的研究,原因是 下面的自定义tabbar放置加号按钮的方 ...
- Oracle 中 for update 和 for update nowait 的区别
原文出处http://bijian1013.iteye.com/blog/1895412 一.for update 和 for update nowait 的区别 首先一点,如果只是select 的话 ...
- PDF.NET框架操作——工具应用(一)
PDF.NET是个开源的项目其解决UI层(WinForm / Web)控件数据绑定.映射与查询: BLL层实体对象查询(OQL):DAL层SQL语句和.NET数据访问代码映射(查看 SQL-MAP ...
- anroid ndk编译ffmpeg 引用librtmp libx264
Ffmpeg 无处不在,自然android系统少不了它,折腾了不少时间完成 ndk编译ffmpeg,生成so库中引用了外部库librtmp,libx264.条条大路通罗马, 也许还有别的更好的方法去完 ...
- uoj 67 新年的毒瘤 割点
题目链接: 题目 #67. 新年的毒瘤 问题描述 辞旧迎新之际,喜羊羊正在打理羊村的绿化带,然后他发现了一棵长着毒瘤的树. 这个长着毒瘤的树可以用 nn 个结点 mm 条无向边的无向图表示.这个图中有 ...
- 解决Tomcat 7遇到StackOverflowError的异常
参考网址:http://qingyuexiao.iteye.com/blog/1886059 前言:在写此博客前,首先感谢姚双琪.林瑞丰.网友qingyuexiao的倾囊相助!此博文不过是笔者对于他们 ...
- 让你网页同时兼容FireFox和IE
CSS 兼容要点:DOCTYPE 影响 CSS 处理 FireFox: div 设置 margin-left, margin-right 为 auto 时已经居中, IE 不行. FireFox: b ...
- 基于Pre-Train的CNN模型的图像分类实验
基于Pre-Train的CNN模型的图像分类实验 MatConvNet工具包提供了好几个在imageNet数据库上训练好的CNN模型,可以利用这个训练好的模型提取图像的特征.本文就利用其中的 “im ...
- DataRow.RowState 属性
RowState 的值取决于两个因素:已对该行执行的操作的类型,以及是否已对 DataRow 调用了 AcceptChanges. private void DemonstrateRowState() ...