zoukankan      html  css  js  c++  java
  • [2018.5.24集训]山景城-博弈论

    题目大意

    绝顶聪明的A和B在一棵树上博弈。

    A的目标是进行最少次数的操作,使B到达节点t。每回合A可以进行三种决策:
    1.不操作(这不算操作次数) 2.切断一条树上的边 3.消除一条边上B留下的标记。

    B初始位于节点s,目标是在到达t之前使A进行尽可能多的操作。
    每回合,若B所处节点存在没有被切断也没有留下标记的边,则B必须从这些边之中选择一条走过去,并在这条边上做标记,否则原地不动。

    求A的最终操作次数。

    部分分:s和t之间有一条边。

    题解

    假定令t为树根。

    首先考虑部分分。
    观察可知,最后B一定会走到一个死路,然后A在封锁B所在节点到t上的其他边后,沿路进行消除标记操作强行让B到达t。
    并且,A在B走到死路之前进行的消除标记操作是不优的,会导致B的下一步的选择变多,即使不会改变最优答案,将来再消除和现在消除的总次数也是一样的,该切断的边也还是要切,不如优先假定消除标记操作全部在最后进行。

    然后考虑一个dp:设 $f_i$ 代表B第一次来到 $i$ 节点,并被A强制送回 $i$ 节点这段时间内,A的总操作次数。

    那么显然每次A会选择切掉当前点和子树中 $f$ 值最大的点相连的边,而B会选择次大值向下走。
    同时,在将B引到当前节点时,应确保当前节点周围的边除了通往t的边和B到达这个位置的边之外的边全部被切断。因此有转移方程:

    $$f_u = deg_u-2 + mathrm{second max}_{v in child_u}{f_v}$$

    最后得到的 $f_s$ 即为部分分答案!

    对于原问题,令可以发现B多出了操作:向上走,而A不能切断s到t之间的边,否则B将无法到达t。
    于是只能让B随意往上走,但一旦中途B选择进入某个儿子,B下一次在链上就是被A强制移动了。

    首先对这条链上的每个节点进行一次dp,接下来的操作包括这次dp均不考虑这些点在s-t链上的儿子。
    在dp结束后,给当前点的每个儿子的 $f$ 值加上它到t路径上所节点的儿子数量,因为要防止B再次进入另一个儿子从而带来负收益。
    因此,现在每个链上节点的儿子的 $f$ 值,代表了若B选择进入当前儿子后,剩余需要完成目标的花费。

    直接对链dp不太好做,那么考虑二分答案。
    考虑如何判断一个答案是否合法:
    从s到t依次枚举链上的节点,令s为1号节点,则在B到达 $i$ 号节点并做出下一步决策前,$A$ 可以有 $i$ 次操作机会。

    假如当前二分值为 $lim$。
    设 $x$ 为为了使答案合法,目前为止至少需要使用的操作次数。
    对于节点 $i$ 的儿子 $v$,若 $x+f_v>lim$,则在B在 $i$ 节点上并还未做出下一步决策之前,$x$ 与 $v$ 之间的边必须切断,否则若B选择进入 $v$ ,答案将不合法。

    于是,判定条件为,在扫完 $i$ 的所有儿子后,$x$ 加上 $i$ 需要切断的儿子数,若 $x>i$ 或 $x>lim$,则 $lim$ 不合法。

    于是二分一发就完成了~

    代码:

    #include<cstdio>
    #include<vector>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    
    inline int read()
    {
    	int x=0;char ch=getchar();
    	while(ch<'0' || '9'<ch)ch=getchar();
    	while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
    	return x;
    }
    
    const int N=1e6+9;
    
    int n,s,t,p,las;
    vector<int> g[N];
    int f[N],fa[N];
    int stk[N],top;
    
    inline void dfs(int u)
    {
    	for(int i=0,v;i<g[u].size();i++)
    		if((v=g[u][i])!=fa[u])
    		{
    			fa[v]=u;
    			dfs(v);
    		}
    }
    
    inline void dfs2(int u)
    {	
    	if(!g[u].size())
    	{
    		f[u]=0;
    		return;
    	}
    	int mx1=0,mx2=0;
    	for(int i=0;i<g[u].size();i++)
    	{
    		dfs2(g[u][i]);
    		if(f[g[u][i]]>=mx1)
    			mx2=mx1,mx1=f[g[u][i]];
    		else if(f[g[u][i]]>mx2)
    			mx2=f[g[u][i]];
    	}
    	f[u]=mx2+g[u].size();
    }
    
    namespace faq
    {
    	inline bool check(int x)
    	{
    		int must=0;
    		for(int i=1;i<=top;i++)
    		{
    			int cnt=0;
    			for(int j=0;j<g[stk[i]].size();j++)
    				if(f[g[stk[i]][j]]+must>x)
    					cnt++;
    			must+=cnt;
    			if(must>i || must>x)return 0;
    		}
    		return 1;
    	}
    
    	int mina()
    	{
    		dfs2(s);
    		stk[top=1]=s;
    		for(int x=fa[s],las=s;x!=t;las=x,x=fa[x])
    		{
    			stk[++top]=x;
    			g[x].erase(find(g[x].begin(),g[x].end(),las));
    			dfs2(x);
    		}
    
    		int tot=0;
    		for(int i=top;i>=1;i--)
    		{
    			tot+=g[stk[i]].size();
    			for(int j=0;j<g[stk[i]].size();j++)
    				f[g[stk[i]][j]]+=tot;
    		}
    
    		int l=0,r=n,mid,ans=n;
    		while(l<=r)
    		{
    			mid=l+r>>1;
    			if(check(mid))
    				ans=mid,r=mid-1;
    			else
    				l=mid+1;
    		}
    
    		printf("%d
    ",ans);
    		return 0;
    	}
    }
    
    int main()
    {
    	n=read();t=read();s=read();
    	for(int i=2,u,v;i<=n;i++)
    	{
    		u=read();v=read();
    		g[u].push_back(v);
    		g[v].push_back(u);
    	}
    
    	if(s==t)return puts("0"),0;
    
    	dfs(t);return 0;
    	for(int i=1;i<=n;i++)
    		if(i!=t)g[i].erase(find(g[i].begin(),g[i].end(),fa[i]));
    
    	return faq::mina();
    }
    
  • 相关阅读:
    不务正业系列-浅谈《过气堡垒》,一个RTS玩家的视角
    [LeetCode] 54. Spiral Matrix
    [LeetCode] 40. Combination Sum II
    138. Copy List with Random Pointer
    310. Minimum Height Trees
    4. Median of Two Sorted Arrays
    153. Find Minimum in Rotated Sorted Array
    33. Search in Rotated Sorted Array
    35. Search Insert Position
    278. First Bad Version
  • 原文地址:https://www.cnblogs.com/zltttt/p/9091238.html
Copyright © 2011-2022 走看看