HDU 4200 Bad Wiring(高斯消元)

227 篇文章 0 订阅
97 篇文章 0 订阅

传送门

Bad Wiring

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


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

题目大意:

给了 n 个灯 n 个开关,第 i 个开关可以控制 id —— i+d 之间的灯全部发生变化,现在给你 n 个灯的初始状态,让你求使这些灯全部关闭的最小步数。

解题思路:

这就是一个裸的高斯消元,但是有一些需要注意的问题,就是那个自由变元可能在中间,这就有点恶心了,我调了好久才发现这个错误,都是 POJ 数据太弱,我以为以前的模板应该没什么问题呢。。。不说啦 上代码

My Code

/**
2016 - 09 - 13 上午
Author: ITAK

Motto:

今日的我要超越昨日的我,明日的我要胜过今日的我,
以创作出更好的代码为目标,不断地超越自己。
**/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 1e9+5;
const int MAXN = 400;
const int MOD = 1e9+7;
const double eps = 1e-7;
const double PI = acos(-1);
using namespace std;
LL Scan_LL()///输入外挂
{
    LL res=0,ch,flag=0;
    if((ch=getchar())=='-')
        flag=1;
    else if(ch>='0'&&ch<='9')
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;
}
int Scan_Int()///输入外挂
{
    int res=0,ch,flag=0;
    if((ch=getchar())=='-')
        flag=1;
    else if(ch>='0'&&ch<='9')
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;
}
void Out(LL a)///输出外挂
{
    if(a>9)
        Out(a/10);
    putchar(a%10+'0');
}

int equ, var;///equ个方程 var个变量
int a[MAXN][MAXN];///增广矩阵
int x[MAXN];///解集
int x_i[MAXN];
bool free_x[MAXN];///判断是不是自由变元
int free_num;///自由变元的个数
int Solve()
{
    int sum = 0;
    for(int i=0; i<var; i++)
        sum += x[i];
    return sum;
}
void Gauss()
{
    int Max_r;///当前列绝对值最大的存在的行
    ///col:处理当前的列
    int row,col = 0;
    int free_x_num;
    int free_index;
    free_num = 0;
    for(row=0; row<equ&&col<var; row++,col++)
    {
        Max_r = row;
        for(int i=row+1; i<equ; i++)
            if(abs(a[i][col]) > abs(a[Max_r][col]))
        Max_r = i;
        if(a[Max_r][col] == 0)
        {
            row--;
            continue;
        }
        if(Max_r != row)
            for(int i=col; i<var+1; i++)
                swap(a[row][i], a[Max_r][i]);
        ///消元
        for(int i=row+1; i<equ; i++)
            if(a[i][col])
                for(int j=col; j<var+1; j++)
                    a[i][j] ^= a[row][j];
    }
    for(int i=row; i<equ; i++)
        if(a[i][col])
        {
            puts("impossible");
            return;
        }
    ///保证对角线主元非 0
    for(int i=0; i<equ; i++)
    {
        if(!a[i][i])
        {
            int j;
            for(j=i+1; j<var; j++)
                if(a[i][j])
                    break;
            if(j == var)
                break;
            for(int k=0; k<equ; k++)
                swap(a[k][i], a[k][j]);
        }
    }
    int tmp = var - row;
    int ans = INF, all = (1<<tmp);
    for(int i=0; i<all; i++)
    {
        int tp = i, p = equ - 1;
        while(tp)
        {
            x[p--] = (tp&1);
            tp>>=1;
        }
        for(int ii=row-1; ii>=0; ii--)
        {
            x[ii] = a[ii][var];
            for(int j=ii+1; j<var; j++)
                x[ii] ^= (a[ii][j] && x[j]);
        }
        ans = min(Solve(), ans);
    }
    printf("%d\n",ans);
}
void Debug()
{
    puts("");
    cout<<"+++++++++++++++++++++++++++分界线++++++++++++++++++++++++++++++"<<endl;
    for(int i=0; i<equ; i++)
    {
        for(int j=0; j<var+1; j++)
        {
            cout<<a[i][j]<<" ";
        }
        cout<<endl;
    }
    cout<<"+++++++++++++++++++++++++++分界线++++++++++++++++++++++++++++++"<<endl;
    puts("");
}
int n, D;
void Init()
{
    memset(a, 0, sizeof(a));
    memset(x, 0, sizeof(x));
    for(int i=0; i<n; i++)
    {
        int ta = max(i-D, 0);
        int tb = min(i+D, n-1);
        for(int j=ta; j<=tb; j++)
            a[j][i] = 1;
    }
}

int main()
{
    int T;
    T = Scan_Int();
    while(T--)
    {
        n = Scan_Int();
        D = Scan_Int();
        equ = var = n;
        Init();
        for(int i=0; i<n; i++)
            cin>>a[i][var];
        Gauss();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值