BZOJ:1443: [JSOI2009]游戏Game

原题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1443

反正不看题解我是完全想不出系列……

先把棋盘黑白染色,也就是同一对角线上颜色相同,使得一个格子上下左右都不同色。

然后我们会发现,某一个人所走的全部格子颜色都是相同的。

把黑白格子当作点提取出来,放在两边,就变成了二分图,游戏的全过程变得像匈牙利算法的增广。

这提示我们也许跟二分图匹配有关。

如果一个点必定在最大匹配中,而一开始棋子放在了这里小YY只要沿着匹配边走小AA就gg了。

注意这里说的是必定在最大匹配中,所以并不用担心出现走到某个非匹配点后小YY无路可走的情形,此时可以通过伪增广保持最大匹配数不变而使起点不在匹配点中。

对于匈牙利算法,可以通过类似的伪增广找出所有不一定在最大匹配中的点。

对于网络流,未被割掉与源汇相邻的边的点肯定是答案,至于其他可以是答案的点,可以通过走反向边(与匈牙利类似的交错路径)来实现到达汇点或从源点出发可达。也就是在残余网络中源点可达且在二分图靠近源点一侧的点,可到达汇点且在二分图靠近汇点一侧的点(没这俩限制就gg了)都是答案点。(注意建图时建单向边,即反向边初始流量为0)

#include<cstdio>
#include<algorithm>
#define MN 110001
using namespace std;

int read_p,read_ca;
inline int read(){
    read_p=0;read_ca=getchar();
    while(read_ca<‘0‘||read_ca>‘9‘) read_ca=getchar();
    while(read_ca>=‘0‘&&read_ca<=‘9‘) read_p=read_p*10+read_ca-48,read_ca=getchar();
    return read_p;
}
const int fx[4]={1,-1,0,0},fy[4]={0,0,1,-1};
struct na{int y,f,ne;}b[MN];
int n,m,l[MN],be[101][101],nm=0,S,T,num=1,d[MN],g[MN],c[MN],mmh=0;
bool bo[MN],O_O[MN];
char s[101][101];
inline void add(int x,int y,int f){b[++num].y=y;b[num].f=f;b[num].ne=l[x];l[x]=num;}
inline void in(int x,int y,int f){add(x,y,f);add(y,x,0);}
int sap(int x,int f){
    if (x==T) return f;
    int h=0,q;
    for (int i=d[x];i;i=b[i].ne)
    if (b[i].f&&g[x]==g[b[i].y]+1){
        q=sap(b[i].y,min(f-h,b[i].f));
        b[i].f-=q;b[i^1].f+=q;h+=q;d[x]=l[x];
        if (h==f) return h;
        if (g[S]==nm) return h;
    }
    if (!--c[g[x]]) g[S]=nm;++c[++g[x]];d[x]=l[x];
    return h;
}
void dfs(int x,bool B){
    if (bo[x]) return;
    bo[x]=1;O_O[x]^=B;
    for (int i=l[x];i;i=b[i].ne)
    if (b[i].f==B) dfs(b[i].y,B);
}
int main(){
    register int i,j,k;
    n=read();m=read();
    for (i=1;i<=n;i++) scanf("%s",s[i]+1);

    for (i=1;i<=n;i++)
    for (j=1;j<=m;j++) if (s[i][j]==‘.‘) be[i][j]=++nm;
    S=++nm;T=++nm;

    for (i=1;i<=n;i++)
    for (j=1;j<=m;j++)
    if (s[i][j]==‘.‘)
    for (k=0;k<4;k++)
    if (s[i+fx[k]][j+fy[k]]==‘.‘)
    if ((i+j)&1) in(be[i+fx[k]][j+fy[k]],be[i][j],1);else in(be[i][j],be[i+fx[k]][j+fy[k]],1);

    for (i=1;i<=n;i++)
    for (j=1;j<=m;j++)
    if (s[i][j]==‘.‘) if (mmh++,O_O[be[i][j]]=((i+j)&1)) in(be[i][j],T,1);else in(S,be[i][j],1);

    for (;g[S]<nm;mmh-=2*sap(S,1e9));
    if (!mmh) return puts("LOSE"),0;
    puts("WIN");
    dfs(S,1);dfs(T,0);
    for (i=1;i<=n;i++)
    for (j=1;j<=m;j++)
    if (s[i][j]==‘.‘&&bo[be[i][j]]&&O_O[be[i][j]]) printf("%d %d\n",i,j);
}

时间: 2024-11-03 21:14:47

BZOJ:1443: [JSOI2009]游戏Game的相关文章

BZOJ1443: [JSOI2009]游戏Game

如果没有不能走的格子的话,和BZOJ2463一样,直接判断是否能二分图匹配 现在有了一些不能走的格子 黑白染色后求出最大匹配 如果是完备匹配,则无论如何后手都能转移到1*2的另一端,故先手必输 否则的话,将棋子放在不是必须点的点上则先手必赢 证明是这样的: 先手先选一个不在最大匹配里面的点,然后对手有两种情况: 一.走一个在最大匹配里的点,然后有了上面考虑错的那种情况,但是不同的是,如果出现了后手最后走某边达到一个非最大匹配中点,就代表出现了一条增广路,显然因为是最大匹配,所以这种情况是不会出现

JSOI2009 游戏

1443: [JSOI2009]游戏Game Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 557  Solved: 251[Submit][Status] Description Input 输入数据首先输入两个整数N,M,表示了迷宫的边长. 接下来N行,每行M个字符,描述了迷宫. Output 若小AA能够赢得游戏,则输出一行"WIN",然后输出所有可以赢得游戏的起始位置,按行优先顺序输出 每行一个,否则输出一行"LOSE

BZOJ 1452: [JSOI2009]Count (二维树状数组)

Description Input Output Sample Input Sample Output 1 2 HINT 二维树状数组的简单应用,c数组的第一维坐标相当于哈希.如果是修改操作,修改前 将当前的值的个数以及祖先都减1, 修改后将个数加1. #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <set> #include

BZOJ 1059 矩阵游戏(神奇的二分图匹配)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1059 题意:给出一个N*N的01矩阵.有两种操作:(1)交换任意两行:(2)交换任意两列.问最后能否使得主对角线上全部为1? 思路:我们发现,对于同一行的两个1,比如 (i,j)和(i,j+1),无论如何我们也不能把这两个1都移动到主对角线上,换句话说,最多能够将其中一个1移动到主对角线上.因为,若我们想将这两 个同时移动到主对角线上,不妨设为(i1,i1),(i2,i2).首先,我们

BZOJ 2438 杀人游戏(强连通分量)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2438 题意:一位冷血的杀手潜入某村庄,并假装成 平民.警察希望能在 N 个人里面,查出谁是杀手. 警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民. 假如查证的对象是杀手, 杀手将会把警察干掉. 现在警察掌握了每一个人认识谁. 每一个人都有可能是杀手,可看作他们是杀手的概率是相同的. 问:根据最优的情况,保证警察自身 安全并知道谁是杀手

[BZOJ 2257][JSOI2009]瓶子和燃料 题解(GCD)

[BZOJ 2257][JSOI2009]瓶子和燃料 Description jyy就一直想着尽快回地球,可惜他飞船的燃料不够了. 有一天他又去向火星人要燃料,这次火星人答应了,要jyy用飞船上的瓶子来换.jyy 的飞船上共有 N个瓶子(1<=N<=1000) ,经过协商,火星人只要其中的K 个 . jyy 将 K个瓶子交给火星人之后,火星人用它们装一些燃料给 jyy.所有的瓶子都没有刻度,只 在瓶口标注了容量,第i个瓶子的容量为Vi(Vi 为整数,并且满足1<=Vi<=10000

BZOJ 1443 JSOI 2009 游戏Game 二分图+博弈

题目大意:给出一个带有坏点的网格图,每次移动棋子到相邻的格子中,要求格子不能重复,问先手是否有必胜策略,如果有,输出所有的棋子可以摆放的初值位置. 思路:很经典的二分图博弈模型,将图黑白染色,就变成了二分图.求最大匹配之后,如果是在二分匹配上的边,每次先手从左侧走到右侧,后手就一定能从右边走回来,这样就是先手输了.具体见:http://blog.sina.com.cn/s/blog_76f6777d0101inwe.html 建立网络流模型,跑最大流,在残量网络上从S能够搜到的左侧的点和右侧的能

BZOJ 1444 JSOI2009 有趣的游戏 AC自动机+矩阵乘法

题目大意:给定n个长度为l的模式串,现在要用前m个大写字母生成一个随机串,每个字符有自己的出现几率,第一次出现的字符串获胜,求最终每个字符串的获胜几率 建出AC自动机,搞出转移矩阵 如果某个节点是模式串那么这个节点只向自己连一条概率为1的出边 然后把转移矩阵自乘50遍即可 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 120 us

●BZOJ 1444 [Jsoi2009]有趣的游戏

题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1444题解.1: 概率dp,矩阵乘法,快速幂. 对所有串建立AC自动机, 那么如果在trie树的节点上转移到一个打了标记的节点,就意味着该标记对应的人取得胜利. (由于题中明确说明串长相同,串又互不相同,所以即表明着建立AC自动机后整个trie树中只有n个打了标记的节点,同时不会存在某些节点无法转移的问题.) 然后建立trie.size×trie.size大小的转移矩阵trans,每个位置t