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;
}
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;
}
相关文章推荐
- JAVA中方法分类、类的分类、监听器的使用
- 在指定的 DSN 中,驱动程序和应用程序之间的体系结构不匹配
- HEX和BIN文件的区别
- CDH clouder manger安装方式
- 115个Java面试题和答案——终极列表(上)
- 正确使用goto语句
- 介绍一个好用的软件--多个WIN远程连接
- c语言--二维数组的首地址问题
- 本地存储
- java虚拟机内存管理机制(二):了解JVM的内存管理与垃圾回收
- epoll
- java运算符
- bash变量
- linux地址映射1、2、3(☆☆☆)
- 使用python将ppm格式转换成jpg
- iOS 表格视图与CoreData配合使用 点击后被点击的cell消失问题
- MySQL触发器
- 大学最重要的七项学习
- wifi驱动分析文档
- 关于ExpandableListView用法的一个简单小例子