Fix the Pond 北师8.7


题目描述:

题意比较麻烦.核心是通过改变开关的横竖来使得从左上到左下可以走到,并且是走一次就能够遍历所有的点恰好一次.
http://acm.bnu.edu.cn/v3/contest_show.php?cid=6416#problem/F

题解:

首先是正解怎么做:(1)转化为联通即可. 一单联通,除了左上和左下的点,其他的点都度都是2.s和t的点是1.那么一但联通,一定满足有一条路径只经过并且都经过每个点一次.(2)怎么贪心的搞联通?这道题目数数初始状态的联通块的数目-1就是答案. 因为相邻的两个联通块随便改一个相邻的墙一定会两个快联通.可以在纸上画一下,题目的开关的性质导致.

其次,比赛时想成网络流…总结如下:
(1)k覆盖模型只能右下(单一不重复即可),不能四个方向都能走.因为像这道题目用k覆盖的模型,就会有4-5-4的环.我们是不能通过网络流来排除的.(并且费用流根本就不能描述开关的花费…哎…..)
(2)k覆盖有两种做法. 两种限制遍历过所有点的限制不同.
(3)欧拉通路. 欧拉回路. 偶然看到网络流解混合图变成欧拉通路

重点:

(1)猜想是不是搞的联通就ok了? 然后用度的性质.
(2)猜想是不是联通块-1就行了?首先是差不多,其次画图推.

代码:
#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 = 1000+10;
const int MAXN = 600*601+10;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};

int vis[maxn][maxn];
int n, m, k;
int a[maxn][maxn];
int cnt;

struct info
{
    int x, y;
    info(int _x=0, int _y=0)
    {
        x = _x;
        y = _y;
    }
};
queue<info> q;

int check(int x, int y)
{
    if(x>=0&&x<n&&y>=0&&y<m)
        return 1;
    return 0;
}
void bfs(int ux, int uy)///要用bfs.... 写的麻烦了...
{
    //printf("dfsd %d  %d\n", ux, uy);
    vis[ux][uy] = 1;
    while(!q.empty())
    {
        q.pop();
    }
    q.push(info(ux, uy));
    while(!q.empty())
    {
        int x = q.front().x, y = q.front().y;
        q.pop();
        if((x+y)%2==0)
        {
            int pI, pJ, newI, newJ;
            pI = x, pJ = y;
            if(a[pI][pJ]==1||a[pI][pJ]==0)
            {
                newI = x, newJ = y-1;
                if(check(newI, newJ)&&!vis[newI][newJ])
                {
                    vis[newI][newJ] = 1;
                    q.push(info(newI, newJ));
                }
            }
            if(a[pI][pJ]==2||a[pI][pJ]==0)
            {
                newI = x-1, newJ = y;
                if(check(newI, newJ)&&!vis[newI][newJ])
                {
                    vis[newI][newJ] = 1;
                    q.push(info(newI, newJ));
                }
            }
            pI = x+1, pJ = y+1;
            if(a[pI][pJ]==1||a[pI][pJ]==0)
            {
                newI = x, newJ = y+1;
                if(check(newI, newJ)&&!vis[newI][newJ])
                {
                    vis[newI][newJ] = 1;
                    q.push(info(newI, newJ));
                }
            }
            if(a[pI][pJ]==2||a[pI][pJ]==0)
            {
                newI = x+1, newJ = y;
                if(check(newI, newJ)&&!vis[newI][newJ])
                {
                    vis[newI][newJ] = 1;
                    q.push(info(newI, newJ));
                }
            }
        }
        else
        {
            int pI, pJ, newI, newJ;
            pI = x, pJ = y+1;
            if(a[pI][pJ]==1||a[pI][pJ]==0)
            {
                newI = x, newJ = y+1;
                if(check(newI, newJ)&&!vis[newI][newJ])
                {
                    vis[newI][newJ] = 1;
                    q.push(info(newI, newJ));
                }
            }
            if(a[pI][pJ]==2||a[pI][pJ]==0)
            {
                newI = x-1, newJ = y;
                if(check(newI, newJ)&&!vis[newI][newJ])
                {
                    vis[newI][newJ] = 1;
                    q.push(info(newI, newJ));
                }
            }
            pI = x+1, pJ = y;
            if(a[pI][pJ]==1||a[pI][pJ]==0)
            {
                newI = x, newJ = y-1;
                if(check(newI, newJ)&&!vis[newI][newJ])
                {
                    vis[newI][newJ] = 1;
                    q.push(info(newI, newJ));
                }
            }
            if(a[pI][pJ]==2||a[pI][pJ]==0)
            {
                newI = x+1, newJ = y;
                if(check(newI, newJ)&&!vis[newI][newJ])
                {
                    vis[newI][newJ] = 1;
                    q.push(info(newI, newJ));
                }
            }
        }
    }
}
void solve()
{
    CLR(vis);
    cnt = 0;
    REP(i, 0, n)
    {
        REP(j, 0, m)
        {
            if(!vis[i][j])
            {
                cnt++;
                bfs(i, j);
            }
        }
    }
    printf("%d\n", cnt-1);
}
char str[maxn];
int main()
{
   // freopen("6Fin.txt", "r", stdin);
    //freopen("6Fout.txt", "w", stdout);
    while(scanf("%d", &k) != EOF)
    {
        CLR(a);
        n = 2*k;
        m = 2*k+1;
        REP_D(i, 1, 2*k - 1)
        {
            int start = 2;
            if(i&1)
            {
                start = 1;
            }
            scanf("%s", str);
            for(int j = start, t = 0; t<k; t++,j += 2)
            {
                if(str[t]=='H')
                {
                    a[i][j] = 1;
                }
                else
                {
                    a[i][j] = 2;
                }
            }
        }
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值