您的位置:首页 > 其它

POJ3185 The Water Bowls【高斯消元法】

2015-09-15 11:21 246 查看
题目链接:

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

题目大意:

有 20 只碗排成一列,有的正面向上,有的反面向上。现在要把所有的碗变成正面向

上。已知每次翻转一只碗,这只碗相邻的两只碗也跟着翻转。问:最少翻动几次能将

所有的碗都正面朝上。

解题思路:

很简单的高斯消元解方程,对于有多个自由变元的情况,需要将自由变元枚举一下。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 300;
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(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(j = k; j < Var+1; ++j)
swap(A[k][j],A[MaxRow][j]);
}
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])
return -2;
X[i] = temp / A[i][i] % 2;
}
return 0;
}

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

int Solve()
{
FreeNum = Gauss();
if(FreeNum == -1)
return INF;
else if(FreeNum == 0)
{
int Ans = 0;
for(int i = 0; i < 20; ++i)
Ans += X[i];
return 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] % 2;
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);
}
return Ans;
}
}

int main()
{
Init();
for(int i = 0; i < 20; ++i)
scanf("%d",&A[i][20]);
int Ans = Solve();
if(Ans == INF)
printf("inf\n");
else
printf("%d\n",Ans);

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