POJ 1222 EXTENDED LIGHTS OUT
开关灯问题:每一个开关对四周5点领域都有影响,状态变化:如果灯是亮着的,熄灭;如果灯是熄灭的,亮起。把每一个开关的开闭看做一个未知数x,影响领域看做系数a,每一盏灯现在的状态是y,问题就是
. 等式解释:如果灯是关着的,那么
必须等于0,维持状态;如果灯是开着的,
必须等于1,改变状态。
对于“
5点领域”换个角度看,只有周围的5盏灯会对其产生影响,所以他们的当前系数是1。有:
POJ 1830 开关问题
假设有规模为3*3的9盏灯:
0 1 0
1 0 0
1 1 1
增广矩阵对应的是:
1 1 0 1 0 0 0 0 0 0
1 1 1 0 1 0 0 0 0 1
0 1 1 0 0 1 0 0 0 0
1 0 0 1 1 0 1 0 0 1
0 1 0 1 1 1 0 1 0 0
0 0 1 0 1 1 0 0 1 0
0 0 0 1 0 0 1 1 0 1
0 0 0 0 1 0 1 1 1 1
0 0 0 0 0 1 0 1 1 1
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=905;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
// a[][]:增广矩阵 n: 方程数 m:变量数
void Gauss(int a[N][N],int n,int m,int &r,int &c){
for(r=0,c=0;r<n&&c<m;r++,c++){
int maxi=r;
for(int i=r+1;i<n;i++){
if(abs(a[i][c])>abs(a[maxi][c])) maxi=i;
}
if(maxi!=r){
for(int j=r;j<m+1;j++){
swap(a[r][j],a[maxi][j]);
}
}
if(a[r][c]==0){
r--;
continue;
}
for(int i=r+1;i<n;i++){
if(a[i][c]!=0){
int x=abs(a[i][c]);
int y=abs(a[r][c]);
int lcm=x/gcd(x,y)*y;
int tx=lcm/x;
int ty=lcm/y;
if(a[i][c]*a[r][c]<0) ty=-ty;
for(int j=c;j<m+1;j++){
a[i][j]=(a[i][j]*tx-a[r][j]*ty+2)%2;
}
}
}
}
}
int reback(int a[][N],int n,int m,int r,int c,int x[]){
for(int i=r-1;i>=0;i--){
int t=a[i][c];
for(int j=i+1;j<c;j++) t-=a[i][j]*x[j];
x[i]=t/a[i][i]%2;
x[i]=(x[i]+2)%2;
}
return 0;
}
int a[N][N];
int x[N];
int main(){
int t;
int ca=1;
scanf("%d",&t);
while(t--){
memset(a,0,sizeof(a));
for(int i=0;i<5;i++){
for(int j=0;j<6;j++){
a[6*i+j][6*i+j]=1;
if(i>0) a[6*i+j][6*(i-1)+j]=1;
if(i<4) a[6*i+j][6*(i+1)+j]=1;
if(j>0) a[6*i+j][6*i+j-1]=1;
if(j<5) a[6*i+j][6*i+j+1]=1;
}
}
for(int i=0;i<5;i++){
for(int j=0;j<6;j++) scanf("%d",&a[6*i+j][30]);
}
int r,c;
Gauss(a,30,30,r,c);
reback(a,30,30,r,c,x);
printf("PUZZLE #%d\n",ca++);
for(int i=0;i<30;i++){
if((i+1)%6==0) printf("%d\n",x[i]);
else printf("%d ",x[i]);
}
}
return 0;
}
POJ 1830 开关问题
如果存在自由变元,答案则是2^ans
如果方案唯一,则是2^0。总之就是1<<ans
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=30;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
void Gauss(int a[N][N],int n,int m,int &r,int &c){
for(r=0,c=0;r<n&&c<m;r++,c++){
int maxi=r;
for(int i=r+1;i<n;i++){
if(a[i][c]>a[maxi][c]) maxi=i;
}
if(maxi!=r){
for(int j=r;j<m+1;j++){
swap(a[r][j],a[maxi][j]);
}
}
if(a[r][c]==0){
r--;
continue;
}
for(int i=r+1;i<n;i++){
if(a[i][c]&&a[r][c]){
for(int j=c;j<m+1;j++){
a[i][j]=(a[i][j]-a[r][j]+2)%2;
}
}
}
}
}
// -2 没有整数解 -1:无解 0: 唯一解 m-r:(自由变元个数)无穷多个解
int reback(int a[][N],int n,int m,int r,int c,int x[],bool tag[]){
for(int i=r;i<n;i++) if(a[i][c]!=0) return -1;
if(r<m){
memset(tag,0,sizeof(tag));
for(int i=r-1;i>=0;i--){
int dex=0;
int cnt=0;
for(int j=0;j<m;j++){
if(a[i][j]!=0&&tag[j]==0){
cnt++;
dex=j;
}
}
if(cnt>1) continue;
int t=a[i][m];
for(int j=0;j<m;j++){
if(a[i][j]!=0&&j!=dex){
t-=a[i][j]*x[j];
}
}
x[dex]=t/a[i][dex]%2;
x[dex]=(x[dex]+2)%2;
tag[dex]=1;
}
return m-r;
}
for(int i=r-1;i>=0;i--){
int t=a[i][c];
for(int j=i+1;j<c;j++) t-=a[i][j]*x[j];
if(t%a[i][i]!=0) return -2;
x[i]=t/a[i][i]%2;
x[i]=(x[i]+2)%2;
}
return 0;
}
int e1[N],e2[N];
int a[N][N];
int x[N];
bool tag[N];
int main()
{
//freopen("cin.txt","r",stdin);
int k;
cin>>k;
while(k--){
memset(a,0,sizeof(a));
int N;
scanf("%d",&N);
for(int i=0;i<N;i++) scanf("%d",&e1[i]);
for(int i=0;i<N;i++) scanf("%d",&e2[i]);
for(int i=0;i<N;i++) {
a[i][N]=(e2[i]-e1[i]+2)%2;
a[i][i]=1;
}
int p1,p2;
while(scanf("%d%d",&p1,&p2)){
if(p1+p2==0) break;
a[p2-1][p1-1]=1;
}
int r,c;
Gauss(a,N,N,r,c);
int g=reback(a,N,N,r,c,x,tag);
if(g<0) printf("Oh,it's impossible~!!\n");
else printf("%d\n",1<<g);
}
return 0;
}
POJ 2947 Widget Factory
大意:周期性时间问题,建立模线性方程组。每一个装饰物的加工应该是需要一定人手的,且有一定的工作时间。设每一个装饰物的加工时间为
, 有
例如例一:
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=305;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
void Gauss(int a[N][N],int n,int m,int &r,int &c){
for(r=0,c=0;r<n&&c<m;r++,c++){
int maxi = r;
for(int i=r+1; i<n; i++)
if(a[i][c] > a[maxi][c])
maxi = i;
if(maxi != r)
{
for(int i=r; i<m+1; i++)
swap(a[r][i],a[maxi][i]);
}
if(a[r][c] == 0)
{
r--;
continue;
}
for(int i=r+1; i<n; i++)
{
if(a[i][c] != 0)
{
int LCM = a[i][c]/gcd(a[i][c],a[r][c])*a[r][c];
int tx = LCM / a[i][c];
int ty = LCM / a[r][c];
for(int j=c; j<m+1; j++)
a[i][j] = ((a[i][j] % 7 * tx % 7 - a[r][j] % 7 * ty % 7) % 7 + 7) % 7;
}
}
}
}
//-2 没有整数解 这一情况除去,模线性方程中没有整除的概念
// -1:无解 0: 唯一解 m-r:(自由变元个数)无穷多个解
int reback(int a[][N],int n,int m,int r,int c,int x[],bool tag[]){
for(int i=r;i<n;i++) if(a[i][c]!=0) return -1;
if(r<m) return m-r;
for(int i=r-1;i>=0;i--){
int t=a[i][c];
for(int j=i+1;j<c;j++) {
t-=a[i][j]*x[j]%7;
t=(t%7+7)%7;
}
//if(t%a[i][i]!=0) return -2;
//int ni,y;
//exgcd(t,a[i][i],ni,y);
//ni=(ni%7+7)%7;
//x[i]=t*ni%7;
while(t%a[i][i]!=0) t+=7;
x[i]=t/a[i][i]%7;
if(x[i]<3) x[i]+=7;
}
return 0;
}
int a[N][N];
int x[N];
bool tag[N];
struct StrCmp{
bool operator()(const char *s1,const char *s2)const{
return strcmp(s1,s2)<0;
}
};
map<const char *,int,StrCmp> mp;
int main()
{
//freopen("cin.txt","r",stdin);
mp["SUN"]=0;
mp["MON"]=1;
mp["TUE"]=2;
mp["WED"]=3;
mp["THU"]=4;
mp["FRI"]=5;
mp["SAT"]=6;
int n,m;
while(cin>>n>>m){
if(n+m==0) break;
memset(a,0,sizeof(a));
int k,dex;
char s1[10],s2[10];
for(int i=0;i<m;i++){
scanf("%d%s%s",&k,s1,s2);
a[i][n]=((mp[s2]-mp[s1]+1)%7+7)%7; // fired day counts
for(int j=0;j<k;j++){
scanf("%d",&dex);
a[i][dex-1]=(a[i][dex-1]+1)%7;
}
}
int r,c;
Gauss(a,m,n,r,c);
int g=reback(a,m,n,r,c,x,tag);
if(g>0) printf("Multiple solutions.\n");
else if(g<0) printf("Inconsistent data.\n");
else {
for(int i=0;i<n-1;i++) printf("%d ",x[i]);
printf("%d\n",x[n-1]);
}
}
return 0;
}