• @codeforces



    @description@

    给定一个 2n 个结点的完全二分图,1~n 在左边,n+1~2n 在右边。第 i 个点与第 j+n 个点的边权为 aij,且 aij 互不相同。

    Alice 与 Bob 在这个图上博弈。
    一开始 Alice 选择 "increase" 或 "decrease",Bob 自动得到另一个。然后 Alice 选择点放置棋子,Bob 开始移动棋子,然后他们轮流移动棋子。但是不能移动到曾经到达过的点。

    假如当前玩家选择 "increase",则该玩家接下来应该走一条比上一次边权大的边;反之如果选择 "decrease",应选一条比上一次小的边。
    不能移动的人判负。

    现在,你和评测机斗智斗勇。你可以选你是 Alice 还是 Bob,然后通过你自己的必胜策略战胜评测机。

    (交互过程就不贴过来了,大家可以自己访问原题

    @solution@

    如果你有做过类似的题目(二分图上博弈,如 bzoj1443),你可能会更能够想到这道题的解法。

    首先,你以为 Alice 既能决定 increase/decrease 又能决定起点很厉害?但是你手玩一下发现几乎都是 Bob 赢。
    所以我们尝试构造出 Bob 的必胜策略。

    对于这类二分图上博弈,必胜策略往往是顺着匹配边走。然而这道题边带权,我们不能求最大匹配。
    我们尝试找到一类匹配,使得 Bob 沿着匹配边走是必胜的。以下假设 Alice 选择左侧点,并选择 increase,其他情况类似的。
    Bob 沿着匹配边 (u, v) 前提是走这条匹配边 (u, v) 是合法的,即所有可能的博弈过程中经过 (u, v) 时前一条边都比这条边大。

    假如说上一条匹配边为 (x, y),一种情况是 Alice 无法走 y -> u,即 w(x, y) > w(u, y)。
    另一种情况选择走 y -> u。此时应该有 w(x, y) < w(u, y) 且 w(u, y) > w(u, v)。
    即 w(x, y) > w(u, y) 或 w(u, y) > w(u, v) 时合法,反过来当 w(x, y) < w(u, y) < w(u, v) 时该匹配不合法。

    带权的匹配?最大权匹配貌似不能应用于这道题。但是我们可以采用另一种带权匹配:稳定婚姻匹配(可以自行百度)。
    我们把左边的点按 w 从小到大评估,右边的点按 w 从大到小评估,跑稳定婚姻匹配。
    那么对于匹配的点对 (x, y) 与 (u, v),不会出现 w(u, v) > w(u, y) 且 w(x, y) < w(u, y) 的情况。即上述的不合法情况。

    至于为什么 Bob 必胜,因为是完全图所以每个点都有匹配。
    那么 Alice 无论走哪里,Bob 总可以找到对策。最后只可能 Alice 没有对策。

    注意上面只讨论了一种情况:Alice 选择左侧点,并选择 increase。其他情况还需要进一步讨论。

    @accepted code@

    #include <cstdio>
    #include <cstdlib>
    using namespace std;
    const int MAXN = 50;
    bool cmp(int x, int y, bool t) {
    	if( !t ) return x > y;
    	else return x < y;
    }
    // x 优于 y ? 
    int a[MAXN + 5][MAXN + 5], n;
    bool tg[MAXN + 5][MAXN + 5];
    int lnk[2*MAXN + 5];
    void get_match(bool t) {
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			tg[i][j] = false;
    	for(int i=1;i<=2*n;i++)
    		lnk[i] = 0;
    	while( true ) {
    		bool flag = true;
    		for(int i=1;i<=n;i++)
    			if( !lnk[i] ) {
    				int mx = 0;
    				for(int j=1;j<=n;j++)
    					if( !tg[i][j] && (mx == 0 || cmp(a[i][j], a[i][mx], t)) )
    						mx = j;
    				if( !lnk[mx+n] )
    					lnk[i] = mx + n, lnk[mx+n] = i;
    				else if( cmp(a[i][mx], a[lnk[mx+n]][mx], !t) ) {
    					int x = lnk[mx+n];
    					lnk[i] = mx + n, lnk[mx+n] = i;
    					tg[x][mx] = true, lnk[x] = 0;
    				}
    				else tg[i][mx] = true;
    				flag = false;
    			}
    		if( flag ) break;
    	}
    }
    /*
    男左女右 
    0 : 男大女小
    1 : 女大男小
    */ 
    void solve() {
    	scanf("%d", &n);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			scanf("%d", &a[i][j]);
    	puts("B"), fflush(stdout);
    	char str[5] = {}; int x;
    	scanf("%s%d", str, &x);
    	get_match( (str[0] == 'I') == (x <= n) );
    	while( true ) {
    		printf("%d
    ", lnk[x]), fflush(stdout);
    		int op;
    		scanf("%d", &op);
    		if( op == -1 ) return ;
    		else if( op == -2 ) exit(0);
    		else x = op;
    	}
    }
    int main() {
    	int t; scanf("%d", &t);
    	while( t-- ) solve();
    }
    

    @details@

    一开始没有看到不能经过已经访问过的点,想了半天。。。

    关于稳定婚姻匹配的过程,这里附上一个简要版的,供以后复习用:
    左边的男生不断去尝试右边还没有拒绝过他且他最喜欢的女生,女生从当前追求她的男生中选择最喜欢的作为暂时的伴侣。最终一定可以得到稳定婚姻匹配。
    首先所有人都会有匹配,否则一个男生一定追求了所有女生,而所有女生一旦被追求就不会单身。矛盾。
    男生不可能会与更喜欢的女生私奔,因为之前肯定已经追求过了,而女生的伴侣一定是越来越优,所以他就越来越没有机会。

    理论上是 O(N^2) 的,每一对关系只会被 check 一次(被拒绝过就不会再追求)
    但是好像没人卡这个时间。。。

    同时,这个匹配是男生最优 (male-optimal) 且女生最差 (female-pessimal) 的匹配方案。

  • 相关阅读:
    RocketMQ系列(一)基本概念
    怎样实现登录?| Cookie or JWT
    Hotspot GC研发工程师也许漏掉了一块逻辑
    初级Java工程师也能轻松进行JVM调优了
    自动化不知如何参数化(二)?xlrd来帮你解决
    自动化不知如何参数化(一)?xlrd来帮你解决
    SpringCloud系列之API网关(Gateway)服务Zuul
    SpringCloud系列之客户端负载均衡Netflix Ribbon
    SpringCloud系列之使用Feign进行服务调用
    Spring Security系列之极速入门与实践教程
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/11846799.html
Copyright © 2020-2023  润新知