您的位置:首页 > 其它

[Gauss]POJ1222 EXTENDED LIGHTS OUT

2014-12-10 20:28 344 查看
题意:给一个5*6的矩阵

1代表该位置的灯亮着, 0代表该位置的灯没亮

按某个位置的开关,可以同时改变 该位置 以及 该位置上方、下方、左方、右方, 共五个位置的灯的开、关(1->0, 0->1)

问能否将所有的灯关闭 若能 输出需要按哪些地方; 不能输出-1

高斯消元的入门题。

每个位置可以列出一个方程, 列出增广矩阵:

  每个位置可以形成增广矩阵的一行, 每行都有30个系数 分别代表(0到29号灯), 将 可以影响该位置改变的 位置(自己、上、下、左、右)对应的置1, 其余置0

  这样就形成了30*30的系数矩阵。

  将初始状态置入最后一列 就形成了增广矩阵

接下来只要解方程组即可。

化成约化阶梯后最后一列即为该方程组的解。

P.s. 需要注意的是:因为是矩阵表示的是灯的开关状态,所以解的过程中不应出现0、1以外的其余数字 即 01方程 用异或求解

int a[300][300];  // 增广矩阵
int x[300];  // 解
int free_x[300]; // 标记是否为自由未知量

int n, m;
void debug()
{
for(int i=0;i<n*n;i++)
{
for(int j=0;j<n*n;j++)
printf("%d ", a[i][j]);
printf("\n");
}
}

void Gauss(int n, int m) // n个方程 m个未知数 即 n行m+1列
{
//转换为阶梯形式
int col=0, k, num=0;
for(k=0;k<n && col<m;k++, col++)
{//枚举行
int max_r=k;
for(int i=k+1;i<n;i++)//找到第col列元素绝对值最大的那行与第k行交换
if(abs(a[i][col])>abs(a[max_r][col]))
max_r=i;
if(max_r!=k)// 与第k行交换
for(int j=col;j<m+1;j++)
swap(a[k][j], a[max_r][j]);
if(!a[k][col])// 说明该col列第k行以下全是0了
{
k--;
free_x[num++]=col;
continue;
}
for(int i=k+1;i<n;i++)// 枚举要删除的行
if(a[i][col])
for(int j=col;j<m+1;j++)
a[i][j]^=a[k][j];
}

//    debug();
//    printf("%d %d\n", col, k);
//
//    for(int i=k;i<n;i++)
//        if(a[i][col])
//            return -1; // 无解

//    if(k<m)   //m-k为自由未知量个数
//    {
//        int stat=1<<(m-k);
//        int ans=INT_MAX;
//        for(int i=0;i<stat;i++)
//        {
//            int cnt=0;
//            for(int j=0;j<m-k;j++)
//                if(i&(1<<j))
//                {
//                    x[free_x[j]]=1;
//                    cnt++;
//                }
//                else
//                    x[free_x[j]]=0;
//            for(int j=k-1;j>=0;j--)
//            {
//                int tmp;
//                for(tmp=j;tmp<m;tmp++)
//                    if(a[j][tmp])
//                        break;
//                x[tmp]=a[j][m];
//                for(int l=tmp+1;l<m;l++)
//                    if(a[j][l])
//                        x[tmp]^=x[l];
//                cnt+=x[tmp];
//            }
//            if(cnt<ans)
//                ans=cnt;
//        }
//        return ans;
//    }
//
//  唯一解 回代
for(int i=m-1;i>=0;i--)
{
x[i]=a[i][m];
for(int j=i+1;j<m;j++)
x[i]^=(a[i][j] && x[j]);
}
//    int ans=0;
//    for(int i=0;i<n*n;i++)
//        ans+=x[i];
//    return ans;
}

void init()
{
n=5, m=6;
memset(a, 0, sizeof(a));
memset(x, 0, sizeof(x));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
int t=i*m+j;
a[t][t]=1;
if(i>0)
a[(i-1)*m+j][t]=1;
if(i<n-1)
a[(i+1)*m+j][t]=1;
if(j>0)
a[i*m+j-1][t]=1;
if(j<m-1)
a[i*m+j+1][t]=1;
}
}

int main()
{
int t, ca=1;
scanf("%d", &t);
while(t--)
{
init();
for(int i=0;i<n*m;i++)
scanf("%d", &a[i][n*m]);
printf("PUZZLE #%d\n", ca++);
Gauss(n*m, n*m);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
printf("%d", x[i*m+j]);
if(j==5)
printf("\n");
else
printf(" ");
}
}
return 0;
}


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