zoukankan      html  css  js  c++  java
  • 【loj


    description

    在一个有向无环图上,阿燐和阿空第 (0) 个时刻分别站在编号为 (s_r, s_k) 的节点,二人都知道双方的初始位置,对地图完全了解。

    从第 (1) 个时刻起,每个时刻阿燐和阿空都可以选择站着不动,也可以选择移动到相邻的节点,二人每时刻的移动是同时开始的,并且不能中途改变方向。

    阿燐被阿空捉住时,游戏立即结束。如果阿空一直没有捉住阿燐,第 (t) 个时刻结束后两人就不能再继续移动了,游戏将在第 (t+1) 个时刻结束。

    阿空的目的是尽快捉住阿燐(捉住的定义是与阿燐同一时刻站在同一节点),而阿燐的目的是尽可能更长时间不被阿空捉住。

    具体而言,若一场游戏进行了 (t_0) 时刻,阿燐的得分是 (t_0),阿空的得分是 (-t_0),双方都希望自己得分(或得分的期望值)更高。

    我们认为在这个过程中阿燐和阿空随时都能知道对方的位置。两人在第 (t) 个时刻不能看出第 (t+1) 个时刻对方要走到哪里。

    恋恋想知道,在双方最优决策的情况下,游戏结束时刻的期望值是多少。

    problem link。

    solution

    显然动态规划,只需要考虑如何转移,发现转移是一个零和博弈问题。

    以下假设阿燐有 (m) 种选择,阿空有 (n) 种选择,阿空的第 (i) 种选择与阿燐的第 (j) 种选择的价值为 (t_{i,j}),阿燐要最大化 (t),阿空要最小化 (t)

    这个零和博弈过程其实就是纳什均衡。考虑纳什均衡的结论:双方按一定概率进行选择,如果任意一方改变策略无法使自己获利,则达到稳定态。

    然后发现其实就是解线性规划。建线性规划方法较多,这里贴一种比较方便的:

    设最终稳定态的价值为 (V),考虑阿空的策略为以概率 (p_i(1leq ileq m)) 选第 (i) 种选择,则有:

    [egin{aligned} mathrm{minimize} V \ egin{cases} sum p_i = 1 \ sum p_it_{ij} leq V end{cases} end{aligned} ]

    考虑消掉等式 (sum p_i = 1)。作换元 (x_i=frac{p_i}{V}),得到标准型:

    [mathrm{maximize} sum x_i \ sum x_it_{ij}leq 1 ]


    关于线性规划的单纯形法(参考了学长的blog),作为个人复习用。不会证明,懒得证明。

    标准型:

    [egin{aligned} mathrm{maximize}sum & c_ix_i \ sum a_{ij}x_j & leq b_i \ x_i & geq 0 end{aligned} ]

    松弛型:

    [egin{aligned} mathrm{maximize}sum & c_ix_i \ b_i - sum a_{ij}x_j & = x'_{i} \ x_i,x'_i & geq 0 end{aligned} ]

    其中 (x_i) 为基变量,(x_i') 为非基变量。


    定义 转轴(pivot)操作 为交换非基变量 (x'_l) 与基变量 (x_e) 的操作。

    由于 (b_l -sum_{p ot = e} a_{lp}x_p-a_{le}x_e=x_l'),故 (x_e = frac{1}{a_{le}}(b_l-sum_{p ot = i} a_{lp}x_p - x_l')),代入其他式子即可。

    如果我们通过转轴最终得到如下的线性规划式子:

    [egin{aligned} mathrm{maximize}sum & c_ix_i + S(c_ileq0) \ b_i - sum a_{ij}x_j & = x'_{i}(b_igeq 0) \ x_i,x'_i & geq 0 end{aligned} ]

    则直接令 (x_i=0,x_i'=b_i) 即可得到线性规划最大值 (S)


    分两步做:找到 (b_igeq 0) 的初始解;不断转轴使得所有 (c_ileq 0)

    (1)找初始解:

    上面的 blog 里提到了一种准确的方法 但是好像没什么人写

    有一个好写点的随机算法:随机取 (b_i < 0),再随机取 (a_{ij}<0),转轴 (x'_i,x_j)。这样至少能够保证转轴后 (b_i geq 0) (显然这个可能会WA)

    (2)使得所有 (c_ileq 0)

    找到任意 (j) 满足 (c_j>0)(c_j) 最大(不是最大也合法,但是贪心地取最大应该或许大概要快些)。

    再找到 (i) 满足 (a_{ij}>0)(frac{b_i}{a_{ij}}) 最小(不是最小不合法)。

    转轴 (x_i',x_j)。可以发现这样不会使得 (b_i < 0) 发生。

    如果找不到初始解,则无解;如果在第二步时不存在 (a_{ij} > 0),则无界。

    code

    #include <cmath>
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    #define rep(i, x, n) for(int i=x;i<=n;i++)
    
    const double EPS = 1E-9;
    
    int dcmp(double x) {return fabs(x) <= EPS ? 0 : (x > 0 ? 1 : -1);}
    
    double a[55][55];
    void pivot(int l, int e, const int &n, const int &m) {
    	double t = a[l][e]; a[l][e] = 1;
    	rep(j, 0, m) a[l][j] /= t;
    	rep(i, 0, n) if( i != l && dcmp(a[i][e]) != 0 ) {
    		t = a[i][e], a[i][e] = 0;
    		rep(j, 0, m) {
    			if( !i && !j ) a[i][j] += t * a[l][j];
    			else a[i][j] -= t * a[l][j];
    		}
    	}
    }
    
    double simplex(const int &n, const int &m) {
    	while( true ) {
    		int l = 0, e = 0;
    		rep(j, 1, m) if( dcmp(a[0][j]) > 0 && (!e || dcmp(a[0][j] - a[0][e]) > 0) )
    			e = j;
    		if( !e ) break;
    		rep(i, 1, n) if( dcmp(a[i][e]) > 0 && (!l || dcmp(a[i][0]/a[i][e] - a[l][0]/a[l][e]) < 0) )
    			l = i;
    		if( !l ) return 0;
    		pivot(l, e, n, m);
    	}
    	return 1 / a[0][0];
    }
    
    vector<int>G[25]; double f[25][25][25]; int n;
    double dp(int x, int y, int p) {
    	if( x == y ) return 0;
    	if( p == 0 ) return 1;
    	if( f[x][y][p] != -1 ) return f[x][y][p];
    	
    	int sn = G[x].size(), sm = G[y].size();
    	rep(i, 1, sn) rep(j, 1, sm) dp(G[x][i - 1], G[y][j - 1], p - 1);
    	rep(i, 1, sn) a[i][0] = 1;
    	rep(j, 1, sm) a[0][j] = 1;
    	rep(i, 1, sn) rep(j, 1, sm)
    		a[i][j] = dp(G[x][i - 1], G[y][j - 1], p - 1);
    	a[0][0] = 0; return f[x][y][p] = simplex(sn, sm) + 1;	
    }
    
    int main() {
    	int m, sr, sk, u, v, t;
    	scanf("%d%d%d%d%d", &n, &m, &sr, &sk, &t);
    	rep(i, 1, m) scanf("%d%d", &u, &v), G[u].push_back(v);
    	rep(i, 1, n) G[i].push_back(i);
    	rep(i, 1, n) rep(j, 1, n) rep(k, 1, t) f[i][j][k] = -1;
    	printf("%.3f
    ", dp(sr, sk, t));
    }
    

    details

    这道题由于初始 (b_igeq 0) 所以不需要找初始解。无界即换元前答案为 (0)

  • 相关阅读:
    SQL Server中的事务日志管理(7/9):处理日志过度增长
    SQL Server中的事务日志管理(6/9):大容量日志恢复模式里的日志管理
    如何阻止SELECT * 语句
    SQL Server中的事务日志管理(5/9):完整恢复模式里的日志管理
    SQL Server中的事务日志管理(4/9):简单恢复模式里的日志管理
    SQL Server中的事务日志管理(3/9):事务日志,备份与恢复
    SQL Server中的事务日志管理(2/9):事务日志架构概述
    在SQL Server里如何进行页级别的恢复
    SQL Server中的事务日志管理(1/9):事务日志概况
    第24/24周 数据库维护(Database Maintenance)
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/13329306.html
Copyright © 2011-2022 走看看