poj 1681


题目描述:

解法一:和以前摆格子的题目差不多.但是不一样.这个十字只有一种摆放方式,如果确定了上一行的颜色,那么这一行怎么摆就确定了.因此只需要确定第一行,然后往下走就行.i,j是十字的中心.(ij是否放只与它的上一个有关,并且只有一种放法)
解法二:高斯消元.重点是当有自由变元的时候枚举然后倒着推上去..

题解:

rt

重点:
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)

typedef long long ll;

using namespace std;

const int maxn = 300+100;
const int INF = 1e9;
int dx[]= {-1, 0, 1, 0}, dy[]= {0, 1, 0, -1};
int a[maxn][maxn], x[maxn];
int equ, var;
char s[maxn][maxn];
int free_x[maxn];
int free_num;
int n;

int gauss()
{
    free_num=0;
    int k, col;
    for(k=0, col=0; k<equ&&col<var; k++,col++)
    {
        int max_k=k;
        for(int i=k+1; i<equ; i++)
        {
            if(abs(a[i][col])>abs(a[max_k][col]))
            {
                max_k = i;
            }
        }
        if(a[max_k][col]==0)
        {
            free_x[free_num++]=col;
            k--;
            continue;
        }
        if(k!=max_k)
        {
            for(int i=col; i<=var; i++)
            {
                swap(a[k][i], a[max_k][i]);
            }
        }
        for(int i=k+1; i<equ; i++)
        {
            if(a[i][col])
            {
                for(int j=col+1; j<=var; j++)
                {
                    a[i][j]^=a[k][j];
                }
                a[i][col]=0;
            }
        }
    }
    for(int i=k; i<equ; i++)
    {
        if(a[i][col])
        {
            return -1;
        }
    }
    if(k==var)
    {
        for(int i=var-1; i>=0; i--)
        {
            x[i]=a[i][var];
            for(int j = i+1; j<var; j++)
            {
                x[i] ^= (a[i][j]&x[j]);
            }
        }
        int ans=0;
        for(int i=0; i<var; i++)
        {
            ans += x[i];
        }
        return ans;
    }
    int S = (1<<(var-k))-1;
    int ans = INF;
    int cnt;
    for(int sta=0; sta<=S; sta++)
    {
        cnt=0;
        for(int i=0; i<free_num; i++)
        {
            if(((1<<i)&sta))
            {
                x[free_x[i]]=1;
                cnt++;
            }
            else
            {
                x[free_x[i]]=0;
            }
        }
        for(int i=k-1; i>=0; i--)
        {
            int index=i;
            for(int j=i; j<var; j++)
            {
                if(a[i][j]!=0)
                {
                    index=j;
                    break;
                }
            }
            x[index]=a[i][var];
            for(int j=index+1; j<var; j++)
            {
                x[index]^=(a[i][j]&x[j]);
            }
            cnt += x[index];
        }
        ans = min(cnt, ans);
    }
    return ans;
}

int check(int x, int y)
{
    if(x>=0&&x<n&&y>=0&&y<n)
        return 1;
    return 0;
}
void solve()
{
    equ=n*n;
    var=equ;
    CLR(a);
    CLR(x);
    REP(i, 0, n)
    {
        REP(j, 0, n)
        {
            int tmp=i*n+j;
            if(s[i][j]=='y')
            {
                a[tmp][var]=0;
            }
            else
            {
                a[tmp][var]=1;
            }
            a[tmp][tmp]=1;
            for(int k=0; k<4; k++)
            {
                int newI=i+dx[k], newJ=j+dy[k];
                if(check(newI, newJ))
                {
                    int goal=newI*n+newJ;
                    a[goal][tmp]=1;
                }
            }
        }
    }
    int ans=gauss();
    if(ans==-1)
    {
        printf("inf\n");
    }
    else
    {
        printf("%d\n", ans);
    }
}

int main()
{
    //freopen("4Din.txt", "r", stdin);
    //freopen("4Dout.txt", "w", stdout);
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &n);
        REP(i, 0, n)
        {
            scanf("%s", s[i]);
        }
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值