您的位置:首页 > 大数据 > 人工智能

POJ1681 Painter's Problem【高斯消元法】

2015-09-14 16:28 686 查看
题目连接:

http://poj.org/problem?id=1681

题目大意:

有一个 N*N 的正方形的墙,其中一些墙是白色的,另一些墙是黄色的。Bob 想要把

所有的墙都涂成黄色。但是他的画笔不是很好用。当他涂位置为 (i,j) 的砖时,会将

周围 (i+1,j),(i-1,j),(i,j+1),(i,j-1) 位置上的砖改变颜色(黄色回变成白色,白

色会变成黄色)。现在要计算出 Bob 最少需要涂多少块砖,会将所有的墙变为黄色。

解题思路:

每个位置上的砖最多涂一次,因为涂两次就和没涂是一样的。和

POJ1222 其实是一

样的,不过需要判断是否有解。如果没有解输出 inf。有解的话,再判断是否有不确

定变元。如果没有不确定变元,则方程组有唯一解,将解集加起来,算出 1 的总数,

即为结果。如果含有不确定变元,则二进制枚举出所有不确定变元,得出结果。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 15*15+10;
const int INF = 0xffffff0;

int Equ,Var;
int A[MAXN][MAXN];
int X[MAXN];
bool FreeX[MAXN];
int FreeNum;
int FreeOnly[MAXN];

void Debug()
{
for(int i = 0; i < Equ; ++i)
{
for(int j = 0; j < Var+1; ++j)
cout << A[i][j] << ' ';
cout << endl;
}
}

int GCD(int a,int b)
{
if(b == 0)
return a;
return GCD(b,a%b);
}

int LCM(int a,int b)
{
return a / GCD(a,b) * b;
}

int Gauss()
{
int i,j,k;
int MaxRow;
int col = 0;
int Lcm;
int ta,tb;
int temp;
int FreeXNum = 0;
int FreeIndex;

for(int i = 0; i <= Var; ++i)
{
// X[i] = 0;
FreeX[i] = true;
}

for(k = 0; k < Equ && col < Var; ++k,++col)
{
MaxRow = k;
for(i = k+1; i < Equ; ++i)
{
if(abs(A[i][col]) > abs(A[MaxRow][col]))
MaxRow = i;
}
if(MaxRow != k)
{
for(i = k; i < Var+1; ++i)
swap(A[k][i],A[MaxRow][i]);
}
if(A[k][col] == 0)
{
k--;
FreeOnly[FreeXNum++] = col;
continue;
}
for(i = k+1; 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] < 0)
tb = -tb;
for(j = col; j < Var+1; ++j)
A[i][j] = (A[i][j]*ta%2 - A[k][j]*tb%2 + 2) % 2;
}
}
}

for(i = k; i < Equ; ++i)
{
if(A[i][col])
return -1;
}

if(k < Var)
{
return Var - k;
}

for(i = Var-1; i >= 0; --i)
{
temp = A[i][Var] % 2;
for(j = i+1; j < Var; ++j)
{
if(A[i][j])
temp = (temp - A[i][j]*X[j]%2 + 2) % 2;
}
if(temp % A[i][i] != 0)
return -2;
X[i] = temp / A[i][i] % 2;
}
return 0;
}

void Solve()
{
FreeNum = Gauss();
if(FreeNum == -1)
printf("inf\n");
else if(FreeNum == 0)
{
int Ans = 0;
for(int i = 0; i < Var; ++i)
Ans += X[i];
printf("%d\n",Ans);
}
else
{
int Ans = INF;
for(int i = 0; i < (1 << FreeNum); ++i)
{
int Cnt = 0;
for(int j = 0; j < FreeNum; ++j)
{
if(i & (1<<j))
{
X[FreeOnly[j]] = 1;
Cnt++;
}
else
X[FreeOnly[j]] = 0;
}
for(int j = Var-FreeNum-1; j >= 0; --j)
{
int idx;
for(idx = j; idx < Var; ++idx)
if(A[j][idx])
break;
X[idx] = A[j][Var];
for(int k = idx+1; k < Var; ++k)
{
if(A[j][k])
X[idx] = (X[idx] - X[k] + 2)%2;
}
Cnt += X[idx];
}
Ans = min(Ans,Cnt);
}
printf("%d\n",Ans);
}
}

void Init(int N)
{
memset(A,0,sizeof(A));
memset(X,0,sizeof(X));
Equ = Var = N*N;
for(int i = 0; i < N; ++i)
{
for(int j = 0; j < N; ++j)
{
A[i*N+j][i*N+j] = 1;
if(i > 0)
A[(i-1)*N+j][i*N+j] = 1;
if(i < N-1)
A[(i+1)*N+j][i*N+j] = 1;
if(j > 0)
A[i*N+j-1][i*N+j] = 1;
if(j < N-1)
A[i*N+j+1][i*N+j] = 1;
}
}
}

char s[30][30];

int main()
{
int T,N;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
Init(N);
for(int i = 0; i < N; ++i)
{
scanf("%s",s[i]);
for(int j = 0; j < N; ++j)
{
if(s[i][j] == 'y')
A[i*N+j][N*N] = 0;
else
A[i*N+j][N*N] = 1;
}
}
Solve();
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: