zoukankan      html  css  js  c++  java
  • [题解] [AGC010F] Tree Game

    题面

    题解

    我们取两个点出来分析, 发现如果先手要赢他就必须从他当前的 (i) 点走到 (j) 点, 满足(a_i < a_j)
    不妨固定这棵树的根, 那么每一步都是从上往下走
    因为从下往上走了一步其实是相当于抵消了从上往下走的那一步
    相当于没有从上往下走, 两者的大小关系也没有变
    所以我们就这样限制了操作的方向
    又由于最后肯定会分出输赢来, 所以每一个点要么是先手必胜要么是先手必败
    若这个点必胜, 当且仅当它下一步能够到达的所有点中中有至少一个先手必败的点
    若这个点必败, 当且仅当它下一步能够到达的所有点中没有先手必败的点
    (f[i])(i) 这个点是否先手必胜
    那么有

    [f[u] |= !f[v], v in {Son_u} ]

    对于每一个点作为根的情况都 DP 一次就可以覆盖所有情况了

    Code

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    const int N = 3005; 
    using namespace std; 
    
    int n, a[N], head[N], cnte, f[N];
    struct edge { int to, nxt; } e[N << 1]; 
    
    template < typename T >
    inline T read()
    {
    	T x = 0, w = 1; char c = getchar();
    	while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
    	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    	return x * w; 
    }
    
    inline void adde(int u, int v) { e[++cnte] = (edge) { v, head[u] }, head[u] = cnte; }
    
    void dfs(int u, int fa)
    {
    	for(int v, i = head[u]; i; i = e[i].nxt)
    	{
    		v = e[i].to; if(v == fa) continue;
    		dfs(v, u), f[u] |= !f[v] && (a[v] < a[u]); 
    	}
    }
    
    int main()
    {
    	n = read <int> ();
    	for(int i = 1; i <= n; i++)
    		a[i] = read <int> ();
    	for(int u, v, i = 1; i < n; i++)
    	{
    		u = read <int> (), v = read <int> ();
    		adde(u, v), adde(v, u); 
    	}
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= n; j++)
    			f[j] = 0;
    		dfs(i, 0);
    		if(f[i]) printf("%d ", i); 
    	}
    	puts(""); 
    	return 0; 
    }
    

    这种跟博弈论有关的题做的还是太少了

  • 相关阅读:
    GitLab基本用法
    SSH免密登录详解
    一文搞懂GitLab安装部署及服务配置
    初识:LevelDB
    Jenkins安装与Gitlab项目部署详解
    CentOS7的安装和配置
    C/C++语言的学习方向
    C语言atoi函数
    C语言整数的取值范围
    C语言scanf函数
  • 原文地址:https://www.cnblogs.com/ztlztl/p/12792701.html
Copyright © 2011-2022 走看看