bzoj1443:[jsoi2009]游戏game

嘒彼小星      2022-02-17     425

关键词:

1443: [JSOI2009]游戏Game

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 1334 Solved: 613
[Submit][Status][Discuss]

Description

Input

输入数据首先输入两个整数N,M,表示了迷宫的边长。 接下来N行,每行M个字符,描述了迷宫。

Output

若小AA能够赢得游戏,则输出一行"WIN",然后输出所有可以赢得游戏的起始位置,按行优先顺序输出 每行一个,否则输出一行"LOSE"(不包含引号)。

Sample Input

3 3
.##
...

.

Sample Output

WIN
2 3
3 2

HINT

对于100%的数据,有1≤n,m≤100。 对于30%的数据,有1≤n,m≤5。

题解

黑白染色,可走的点连边,做最大匹配
发现如果先手放到非匹配点上,后手要么无路可走,失败,要么走到匹配点上;如果后手走到匹配点上,先手沿匹配点走,后手要么无路可走,要么走非匹配边,由于不存在增广路,后手走到的一定是一个匹配点。。。。一直这样走下去,发现走的是交替路,由于不存在增广路,交替路的结尾一定是匹配边,后手一定无路可走。此时先手必胜
必胜点即为所有最大匹配方案中的未匹配点
其他点均为必败点(相当于先手走必胜点后,后手不得不走的那个点,因此必败)
怎么求呢?
发现从未匹配点开始,走非匹配边、匹配边后,交换匹配边与非匹配边,匹配合法且最大匹配不变。即我们从每个非匹配点走交替路,然后所有匹配点连过来的点都是答案(即与起点同集合的点)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <string> 
#include <cmath> 
#include <sstream>
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
template<class T>
inline void swap(T &a, T &b)
{
    T tmp = a;a = b;b = tmp;
}
inline void read(int &x)
{
    x = 0;char ch = getchar(), c = ch;
    while(ch < '0' || ch > '9') c = ch, ch = getchar();
    while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
    if(c == '-') x = -x;
}
const int INF = 0x3f3f3f3f;
const int MAXN = 100 + 10;
const int dx[4] = {0,0,1,-1};
const int dy[4] = {1,-1,0,0};
int n, m, hao[MAXN][MAXN], vis1[MAXN * MAXN], vis2[MAXN * MAXN], cnt1, cnt2, lk1[MAXN * MAXN], lk2[MAXN * MAXN], vis[MAXN * MAXN];
char s[MAXN][MAXN];
struct Edge
{
    int u,v,nxt;
    Edge(int _u, int _v, int _nxt){u = _u;v = _v;nxt = _nxt;}
    Edge(){}
}edge[100000];
int head[MAXN * MAXN], cnt;
inline void insert(int a, int b)
{
    edge[++cnt] = Edge(a,b,head[a]);
    head[a] = cnt;
}
int dfs(int x)
{
    for(int pos = head[x];pos;pos = edge[pos].nxt)
    {
        int i = edge[pos].v;
        if(vis[i]) continue;
        vis[i] = 1;
        if(lk2[i] == -1 || dfs(lk2[i]))
        {
            lk2[i] = x, lk1[x] = i;
            return 1;
        }
    }
    return 0;
} 
void dfs1(int x)
{
    vis1[x] = 1;
    for(int pos = head[x];pos;pos = edge[pos].nxt)
    {
        int i = edge[pos].v;
        if(lk2[i] == -1 || vis1[lk2[i]]) continue;
        dfs1(lk2[i]);
    }
}
void dfs2(int x)
{
    vis2[x] = 1;
    for(int pos = head[x];pos;pos = edge[pos].nxt)
    {
        int i = edge[pos].v;
        if(lk1[i] == -1 || vis2[lk1[i]]) continue;
        dfs2(lk1[i]);
    }
}
int main()
{
    read(n), read(m);
    for(int i = 1;i <= n;++ i)
        scanf("%s", s[i] + 1); 
    for(int i = 1;i <= n;++ i)
        for(int j = 1;j <= m;++ j)
            if(s[i][j] == '#') continue;
            else if((i + j & 1)) hao[i][j] = ++ cnt1;
            else hao[i][j] = ++ cnt2;
    //左奇右偶 
    for(int i = 1;i <= n;++ i)
        for(int j = 1;j <= m;++ j)
            if(s[i][j] == '.' && (i + j) & 1)
            {
                for(int k = 0;k < 4;++ k)
                {
                    int x = i + dx[k], y = j + dy[k];
                    if(x <= 0 || x > n || y <= 0 || y > m || s[x][y] == '#') continue;
                    insert(hao[i][j], hao[x][y]);
                }
            }
    memset(lk1, -1, sizeof(lk1));
    memset(lk2, -1, sizeof(lk2));
    for(int i = 1;i <= cnt1;++ i) 
    {
        memset(vis, 0, sizeof(vis));
        dfs(i);
    }
    for(int i = 1;i <= cnt1;++ i)
        if(lk1[i] == -1) dfs1(i);
    cnt = 0;memset(head, 0, sizeof(head));
    for(int i = 1;i <= n;++ i)
        for(int j = 1;j <= m;++ j)
            if(s[i][j] == '.' && (i + j) & 1)
            {
                for(int k = 0;k < 4;++ k)
                {
                    int x = i + dx[k], y = j + dy[k];
                    if(x <= 0 || x > n || y <= 0 || y > m || s[x][y] == '#') continue;
                    insert(hao[x][y], hao[i][j]);
                }
            }
    for(int i = 1;i <= cnt2;++ i)
        if(lk2[i] == -1) dfs2(i);
    int flag = 0;
    for(int i = 1;i <= n;++ i)
        for(int j = 1;j <= m;++ j)
            if(s[i][j] == '#') continue;
            else if((i + j) & 1 && vis1[hao[i][j]])  
            {
                if(!flag) printf("WIN
"), flag = 1;
                printf("%d %d
", i, j);
            }
            else if(!((i + j) & 1) && vis2[hao[i][j]])
            {
                if(!flag) printf("WIN
"), flag = 1;
                printf("%d %d
", i, j);
            }
    if(!flag) printf("LOSE"); 
    return 0;
}

bzoj1443[jsoi2009]游戏game

AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1443分析:对于这种棋子在棋盘上走来走去,只能走相邻的格子的问题,感觉还是挺好玩的...  然后好玩归好玩,可是有点不会做啊.  貌似棋盘上相邻格子这种不断移动的问题,都大概能... 查看详情

bzoj:1443:[jsoi2009]游戏game

...黑白格子当作点提取出来,放在两边,就变成了二分图,游戏的全过程变得像匈牙利算法的增广。这提示我们也许跟二分图匹配有关。如 查看详情

bzoj1444[jsoi2009]有趣的游戏ac自动机+概率dp+矩阵乘法

【BZOJ1444】[Jsoi2009]有趣的游戏DescriptionInput注意是0<=POutputSampleInputSampleOutputHINT 30%的数据保证,n≤2.50%的数据保证,n≤5.100%的数据保证,n,l,m≤10.题解:本题的做法真的很多啊,概率DP,期望DP,当然还有矩乘黑科技~就是先跑AC... 查看详情

bzoj1449[jsoi2009]球队收益

TimeLimit: 5Sec  MemoryLimit: 64MBSubmit: 741  Solved: 423DescriptionInputOutput一个整数表示联盟里所有球队收益之和的最小值。SampleInput331021111010133122331SampleOutput43HINTSource&n 查看详情

bzoj2257:[jsoi2009]瓶子和燃料

2257:[Jsoi2009]瓶子和燃料TimeLimit: 10Sec  MemoryLimit: 128MBDescriptionjyy就一直想着尽快回地球,可惜他飞船的燃料不够了。 有一天他又去向火星人要燃料,这次火星人答应了,要jyy用飞船上的瓶子来换。jyy的飞船上共... 查看详情

bzoj1452:[jsoi2009]count

DescriptionInputOutputSampleInputSampleOutput12HINT  题目传送门 话说这好像是我第一次做树状数组的题树状数组裸题,还是二维的,多一层for而已 代码如下:#include<cmath>#include<cstdio>#include<cstring>#include< 查看详情

bzoj-2257:[jsoi2009]瓶子和燃料(中国剩余定理)

2257:[Jsoi2009]瓶子和燃料TimeLimit: 10Sec  MemoryLimit: 128MBSubmit: 1583  Solved: 965[Submit][Status][Discuss]Descriptionjyy就一直想着尽快回地球,可惜他飞船的燃料不够了。 有一天他又去向火星人要 查看详情

bzoj1560jsoi2009火星藏宝图[dp]

火星藏宝图TimeLimit:10Sec  MemoryLimit:64MB[Submit][Status][Discuss]Description  Input  Output  SampleInput  410  1120  101010  3560  5330SampleOutput  -4HINT  1<=M<=2000,2<=N<=100000 查看详情

bzoj1452:[jsoi2009]count

PS:c<=100(原谅像我一样眼瞎的人吧这题就是一个二维树状数组的模板啊,然后不会,然后学了学,然后好像没难度,自己看代码就会了。。#include<cstdio>#include<iostream>#include<cstring>#include<cstdlib>#include<algorith... 查看详情

bzoj1558[jsoi2009]等差数列

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1558【题解】这题恶心死人了啊。。网络上题解很多都是看代码看代码。。真是太不负责任了。。我这里详细说一下吧。。题解在代码下面。#include<stdio.h>#include<string.h>#include&... 查看详情

bzoj2257:[jsoi2009]瓶子和燃料数论:裴蜀定理

2257:[Jsoi2009]瓶子和燃料TimeLimit:10Sec  MemoryLimit:128MBSubmit:1326  Solved:815[Submit][Status][Discuss]Descriptionjyy就一直想着尽快回地球,可惜他飞船的燃料不够了。有一天他又去向火星人要燃料,这次火星人答应了,要jyy用飞船... 查看详情

[bzoj1452][jsoi2009]count

来自FallDream的博客,未经允许,请勿转载,谢谢。 有一个n*m的矩阵,每个点有一个权值。需要支持两种操作:1)改变一个点的权值2)查询一个矩形内权值为c的个数n,m<=300q<=200000权值<=100权值有点小吧?那就每种权值开一... 查看详情

bzoj1449/bzoj2895[jsoi2009]球队收益/球队预算费用流

题目描述输入输出一个整数表示联盟里所有球队收益之和的最小值。样例输入331021111010133122331样例输出43题解费用流由于存在一个赢一个输,比较难算。我们可以先假设它们都输掉,然后再安排赢的情况。设fi为i还要打的比赛数... 查看详情

bzoj2257:[jsoi2009]瓶子和燃料

Descriptionjyy就一直想着尽快回地球,可惜他飞船的燃料不够了。 有一天他又去向火星人要燃料,这次火星人答应了,要jyy用飞船上的瓶子来换。jyy的飞船上共有N个瓶子(1<=N<=1000),经过协商,火星人只要其中的K个。jyy将K... 查看详情

bzoj2257:[jsoi2009]瓶子和燃料

Descriptionjyy就一直想着尽快回地球,可惜他飞船的燃料不够了。 有一天他又去向火星人要燃料,这次火星人答应了,要jyy用飞船上的瓶子来换。jyy的飞船上共有N个瓶子(1<=N<=1000),经过协商,火星人只要其中的K个。jyy将K... 查看详情

bzoj1449/2895[jsoi2009]球队收益/球队预算最小费用最大流

【BZOJ2895】球队预算Description在一个篮球联赛里,有n支球队,球队的支出是和他们的胜负场次有关系的,具体来说,第i支球队的赛季总支出是Ci*x^2+Di*y^2,Di<=Ci。(赢得多,给球员的奖金就多嘛)其中x,y分别表示这只球队本赛季的... 查看详情

bzoj3875:[ahoi2014&jsoi2014]骑士游戏

3875:[Ahoi2014&Jsoi2014]骑士游戏TimeLimit: 30Sec  MemoryLimit: 256MBDescription 【故事背景】长期的宅男生活中,JYY又挖掘出了一款RPG游戏。在这个游戏中JYY会扮演一个英勇的骑士,用他手中的长剑去杀死入侵村庄的怪兽... 查看详情

jsoi2009count[树状数组]

BZOJ我们可以发现N,M,C都十分的小,那么只要开100个二维BIT来维护就可以了。每种颜色对应一个BIT。然后查询的时候再用二维前缀和来搞搞就可以了。开始在BZOJ时候是T了的,后来才发现是BIT开太大了,导致寻址过慢。#include<bits... 查看详情