HDU 4200

Bad Wiring

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 785    Accepted Submission(s): 263


Problem Description
The ninja Ryu has infiltrated the Shadow Clan fortress and finds himself in a long hallway. Although ninjas are excellent fighters, they primarily rely on stealth to complete their missions. However, many lights are turned on in the hallway, and this way it will not take long before Ryu is spotted by a guard. To remain unseen, Ryu will need to turn off all the lights as quickly as possible.
The hallway contains a sequence of n lights L1......Ln. Some of these lights are turned on. Destroy-ing the lights with his shurikens would be too loud, so he needs to turn them off the old-fashioned way, using light switches. Luckily, there is a switch box nearby with a light switch Si for every light Li. However, after trying one of the switches, he notices something funny. When he 
ips the switch Si, it does not only turn on/off light Li, but also some of the neighboring lights. Ryu notices that there is a parameter D such that 
ipping switch Si turns on/off all the lights L(i-D)......L(i+D), if they exist(This means that S1 turns on/off all the lights L1 ......L(D+1) and Sn turns on/off all the lights L(n-D)......Ln. Of course, if D>=n, then L(D+1) and L(n-D) will not exist either.). Turning on or off lights can attract the attention of the guards, so Ryu would like to turn off all the lights with the minimum number of times 
ipping a switch. Can you help him out?
 

Input
The first line of the input contains a single number: the number of test cases to follow. Each test case has the following format:
1.One line with two integers n (1 <= n <= 100) and D (0 <= D <= 15): the number of lights and the parameter mentioned above.
2.One line with n integers. The i(th) integer describes the current state of light Li, where 0 means off and 1 means on.
 

Output
For every test case in the input, the output should contain one integer on a single line: the minimum number of times Ryu needs to flip a switch to turn off all the lights. If it is impossible to turn off all the lights, then output the string "impossible" instead.
In the first example below,flipping switch S4 followed by S7 will turn off all the lights.
 

Sample Input
  
  
2 7 3 1 1 1 0 0 0 0 5 1 1 0 1 0 1
 

Sample Output
  
  
2 3
 

Source


题意:给出一些排成一列的灯,灯的亮暗用0 1 表示,每盏灯对应一个开关,每次打开或关闭某个开关,都会影响该灯与该灯左边和右边的D盏灯。

   给出等的初始状态,问至少操着几次开关能将等全部关掉。

思路:列出方程组,构造出系数矩阵,进行高斯消元,这里可能得到一些自由变元,应该枚举自由变元的赋值情况,搜索出一种使得增广矩阵的最后一列的1的数量最小的一种自由变元的赋值方案即可。


要特别注意,一般高斯消元只将矩阵化为阶梯形或行最简形,如果那么做,要注意自由变元位于那些列。这里可以将矩阵直接化为标准型,这样最后的几列就是自由变元了。

如图:

对于一个数据:

1
20 12
1 0 0 1 0 0 0 0 0 1 1 1 1 1 1 1 0 1 0 1 
高斯消元后,
行最简形的矩阵如图:


红色标注的列为自由变元。


标准形的矩阵:



代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>

using namespace std;

#define INF 1000000000
#define N 110
#define M 210

int n, d;
bool mat[N][N], val[N];

void print(bool a[N][N], int n)
{
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n+1; j++)
        {
            printf("%d ", a[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}

int dfs(int col, int cnt)
{
    if(col == n+1)
    {
        int res = cnt;
        for(int i = 1; i <= n; i++)
        {
            if(val[i] ^ mat[i][n+1]) res++;
        }
        return res;
    }
    int res = 0;
    for(int i = 1; i <= n; i++)
        val[i] ^= mat[i][col];
    res = dfs(col+1, cnt+1);
    for(int i = 1; i <= n; i++)
        val[i] ^= mat[i][col];

    res = min(dfs(col+1, cnt), res);
    return res;
}

int gauss()
{

    int row = 1;
    int r = n;
    for(int i = 1; i <= r; i++, row++)
    {
        //print(mat, n);
        int p = -1;
        for(int j = row; j <= n; j++)
        {
            if(mat[j][i] == 1)
            {
                p = j;
                break;
            }
        }

        //这里发现底下没有1后,得知当前列为自由变元,移到后面
        if(p == -1)
        {
            for(int j = 1; j <= n; j++)
            {
                swap(mat[j][i], mat[j][r]);
            }
            //print(mat, n);
            r--;
            i--;
            row--;
            continue;
        }
        if(p != row)
        {
            for(int j = i; j <= n+1; j++)
            {
                swap(mat[row][j], mat[p][j]);
            }
        }
        for(int j = 1; j <= n; j++)
        {
            if(mat[j][i] == 1 && j != row)
            for(int k = i; k <= n+1; k++)
            {
                mat[j][k] ^= mat[row][k];
            }
        }
    }

    for(int i = row; i <= n; i++)
    {
        if(mat[i][n+1] == 1)
        {
            return -1;
        }
    }

    memset(val, 0, sizeof(val));
    int ans = dfs(row, 0);

    return ans;
}

int main()
{
    freopen("C:\\Users\\zfh\\Desktop\\in.txt", "r", stdin);
    int t; scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &n, &d);
        memset(mat, 0, sizeof(mat));
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &mat[i][n+1]);
        }
        for(int i = 1; i <= n; i++)
        {
            int st = max(1, i-d), ed = min(n, i+d);
            for(int j = st; j <= ed; j++)
            {
                mat[i][j] = 1;
            }
        }
        int ans = gauss();
        if(ans != -1)
            printf("%d\n", ans);
        else printf("impossible\n");
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值