题解
C - Painter’s Problem
题目:有一个方墙,它是由n*n个小方砖组成的。有些砖是白色的,有些是黄色的。把所有的砖都涂成黄色。一旦用刷子画砖(i,j),(i-1,j),(i+1,j),(i,j-1)和(i,j+1)的砖都会改变颜色。找出应该画的砖块的最小数量,以使所有的砖块变黄。
- 高斯消元
- 样题
#include <iostream>
#include <vector>
#include <string.h>
#include <cstdio>
using namespace std;
typedef long long ll;
#define eps 1e-9
const int MAXN = 250;
struct Guass
{
int var, equ;
bool x[MAXN][MAXN], y[MAXN];
vector<int> free_var;
void clear()
{
memset(x, false, sizeof x);
memset(y, false, sizeof y);
}
void init()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
static char c[20];
scanf("%s", c);
for (int j = 0; j < n; j++)
{
x[i * n + j][i * n + j] = true;
if (j < n - 1)
x[i * n + j][i * n + j + 1] = true;
if (j)
x[i * n + j][i * n + j - 1] = true;
if (i < n - 1)
x[i * n + j][(i + 1) * n + j] = true;
if (i)
x[i * n + j][(i - 1) * n + j] = true;
y[i * n + j] = c[j] == 'w';
}
}
var = equ = n * n;
}
int work()
{
free_var.clear();
int row, col;
for (row = 0, col = 0; row < equ && col < var; row++, col++)
{
int max_row = row;
for (int i = row + 1; i < equ && !x[max_row][col]; i++)
if (x[i][col])
max_row = i;
if (!x[max_row][col])
{
row--;
free_var.push_back(col);
continue;
}
if (row != max_row)
{
for (int j = col; j < var; j++)
swap(x[row][j], x[max_row][j]);
swap(y[row], y[max_row]);
}
for (int i = 0; i < equ; i++)
{
if (i == row)
continue;
if (x[i][col])
{
for (int j = col; j < var; j++)
x[i][j] ^= x[row][j];
y[i] ^= y[row];
}
}
}
for (int i = row; i < equ; i++)
if (y[i] != 0)
return -1;
for (int i = equ; i < var; i++)
free_var.push_back(i);
return free_var.size();
}
} guass;
bool fault[MAXN];
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
guass.clear();
guass.init();
int num = guass.work();
if (num == -1)
puts("inf");
else if (num == 0)
{
int res = 0;
for (int i = 0; i < guass.var; i++)
if (guass.y[i])
res++;
printf("%d\n", res);
}
else
{
int ans = 0x3f3f3f3f;
int tot = (1 << num);
for (int Case = 0; Case < tot; Case++)
{
int cnt = 0;
for (int i = 0; i < num; i++)
{
if (Case&(1 << i))
{
fault[guass.free_var[i]] = true;
cnt++;
}
else
fault[guass.free_var[i]] = false;
}
for (int i = guass.var - num - 1; i >= 0; i--)
{
int idx;
for (idx = i; idx < guass.var; idx++)
if (guass.x[i][idx])
break;
bool flag = guass.y[idx];
for (int cur = idx + 1; cur < guass.var; cur++)
if (guass.x[i][cur])
flag ^= fault[cur];
cnt += flag;
}
ans = min(ans, cnt);
}
printf("%d\n", ans);
}
}
return 0;
}
高斯消元模板题
给定一个线性方程组,对其求解
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define eps 1e-9
const int MAXN = 250;
struct Guass
{
int var, equ;
double x[MAXN][MAXN], y[MAXN];
vector<int> free_var;
void clear()
{
memset(x, false, sizeof x);
memset(y, false, sizeof y);
}
void init()
{
scanf("%d", &var), equ = var;
for (int i = 0; i < equ; i++)
{
for (int j = 0; j < var; j++) scanf("%lf", &x[i][j]);
scanf("%lf", &y[i]);
}
}
//返回-1代表无解,0代表有唯一解,非0正数代表有几个自由变元
int work()
{
free_var.clear();
int row, col;
for (row = 0, col = 0; row < equ&&col < var; row++, col++)
{
//找当前列最大的一列
int max_row = row;
for(int i = row + 1; i < equ; i++)
if(abs(x[i][col]) > abs(x[max_row][col]))
max_row = i;
//存在不能确定的自由变元
if (abs(x[max_row][col]) < eps)
{
row--;
free_var.push_back(col);
continue;
}
//交换
if (row != max_row)
{
for (int i = col; i < var; i++) swap(x[row][i], x[max_row] [i]);
swap(y[row], y[max_row]);
}
//将当前行的第一列的系数化简为1
for (int i = col + 1; i < var; i++) x[row][i] /= x[row][col];
y[row] /= x[row][col];
x[row][col] = 1;
//将其他行的这一列删掉
for (int i = 0; i < equ; i++)
{
if (i == row)continue;
y[i] -= y[row] * x[i][col];
for (int j = col + 1; j < var; j++) x[i][j] -= x[i][col] * x[row][j];
x[i][col] = 0;
}
}
for (int i = row; i < equ; i++) if (abs(y[i]) > eps) return -1;
for (int i = equ; i < var; i++) free_var.push_back(i);
return free_var.size();
}
} guass;
int main()
{
guass.init();
int ans = guass.work();
if (ans != 0) puts("No Solution");
else
{
for (int i = 0; i < guass.var; i++)
{
printf("%.2f\n", guass.y[i]);
}
}
return 0;
}