有一个长度为20的01序列,要将其翻成全0,每次翻动也会将其两侧的字符反转。求最小反转次数。
http://poj.org/problem?id=3185
简单的高斯消元。
将其看成20个变元,20个方程的方程组。
然后就是模板。。。
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
#define pb push_back
#define MP make_pair
#define PII pair<int, int>
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int maxn = 20 + 5;
int equ, var;//equ是方程数(0~equ),var是变元数(0~var)
int a[maxn][maxn];//增广矩阵
int x[maxn];//解集
bool free_x[maxn];//是否是自由变元
int free_num;//自由变元数
int gcd(int a, int b){
return b == 0 ? a : gcd(b, a % b);
}
int lcm(int a, int b){
return a / gcd(a, b) * b;
}
void Debug(){
puts("debug");
for(int i=0; i<equ; i++){
for(int j=0; j<=var; j++)
printf("%d ", a[i][j]);
puts("");
}
puts("end");
}
/*
高斯消元法解方程组.
-2表示有浮点数解,但无整数解;
-1表示无解;0表示唯一解;
大于0表示无穷解,并返回自由变元的个数
*/
int Guass(){
int col = 0;//当前处理的列
int mx;//当前列的最大值
int k;
//Debug();
for(k=0; k<equ && col<var; k++, col++){
mx = k;
for(int i=k+1; i<equ; i++)
if(abs(a[i][col]) > abs(a[mx][col])) mx = i;
if(mx != k){
for(int i=0; i<=var; i++)
swap(a[k][i], a[mx][i]);
}
if(a[k][col] == 0){//全是0,就处理下一列,但行数不变
k--;
continue;
}
for(int i=k+1; i<equ; i++){
if(a[i][col] == 0) continue;
for(int j=col; j<=var; j++)
a[i][j] ^= a[k][j];
}
//Debug();
}
//Debug();
//无解
for(int i=k; i<equ; i++)
if(a[i][var] != 0) return -1;
//有唯一解
if(k == equ){
for(int i=var-1; i>=0; i--){
x[i] = a[i][var];
for(int j=i+1; j<var; j++)
if(a[i][j] && x[j])
x[i] ^= 1;
}
int ans = 0;
for(int i=0; i<var; i++) ans += x[i];
printf("%d\n", ans);
return 0;
}
//有无穷解
for(int i=k-1; i<=0; i--){
free_num = 0;
int idx, tmp;
for(int j=0; j<var; j++)
if(a[i][j] && free_x[j]){
free_num++;
idx = j;
}
if(free_num > 1) continue;
free_x[idx] = 0;
}
int num = var - k, cnt = 0, ans = inf;
int xx[maxn];
for(int i=var-1; i>=0&&cnt<num; i--)//找自由变元
if(free_x[i]) xx[cnt++] = i;
for(int i=0; i<(1 << num); i++){//枚举自由变元
for(int j=0; j<num; j++)
if(i & (1 << j)) x[xx[j]] = 1;
else x[xx[j]] = 0;
for(int j=k-1; j>=0; j--){
int tmp;
for(tmp=j; tmp<var; tmp++)
if(a[j][tmp]) break;
x[tmp] = a[j][var];
for(int l=tmp+1; l<var; l++)
if(a[j][l] && x[l])
x[tmp] ^= 1;
}
int sum = 0;
for(int j=0; j<var; j++)
sum += x[j];
ans = min(ans, sum);
}
printf("%d\n", ans);
return var - k;
}
void init(){
memset(x, 0, sizeof(x));
memset(a, 0, sizeof(a));
memset(free_x, true, sizeof(free_x));
}
int ss[maxn];
int main(){
for(int i=0; i<20; i++)
scanf("%d", &ss[i]);
init();
equ = var = 20;
for(int i=0; i<20; i++){
a[i][var] = ss[i];
a[i][i] = 1;
if(i > 0) a[i][i - 1] = 1;
if(i < 19) a[i][i + 1] = 1;
}
Guass();
return 0;
}