hdu 5005 Compromise (2014 ACMICPC regional Anshan Site 1009)


题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5005


题目巨长,所以不贴题目了,直接说大意(话说大意也不短。。。。)。

题目大意:有两个人A和X,给一个有向无环图(DAG),每一个出度为0的节点(下面称这些节点为“叶子节点”)有两个权值x和y(所有的x,y都不一样,这点非常重要)。除了叶子节点,其他所有节点都都由A或X控制。如果当前位置在非叶子节点U,如果U被A控制,则A可以选择接下来转移的点V(满足U->V存在一条有向边),反之亦然。如果到达了叶子节点,则A得x分,X得y分。现在A和X玩一个游戏,从1节点出发,每个人都希望自己的得分最大(重点)。现在X有一种特殊的操作,他可以告诉A他的策略,所谓策略就是在每个X所控制的点,X会选择的转移节点。(X一定会按照策略行动,至少A是这么认为的)。现在问两个问题:

1.X不使用特殊操作时,所能得到的最大分数。

2.X使用特殊操作时,所能得到的最大分数。


思路:第一问无比简单,因为是DAG,设dp[i][0],dp[i][1]分别表示在i节点A和X所能得到的最大得分。然后分叶子节点,A控制的节点,X控制节点三种情况进行转移即可,应该都会。

关键是第二问,乍一看来好像告诉对方自己的策略是一种愚蠢的行为,并不会对最后的得分有多少改进,但是考虑到双方的目标都是使得自己的得分最大,而不是要使对方的得分最小或是自己和对方的差值最大(这点很重要)。所以X可以采用一种策略使得自己的得分比不使用特殊操作更大,具体看样例即可。至于怎么制定自己的策略,直接制定貌似很难(我不会而已),我们可以换一种思路,因为A,X最后的得分一定是一个叶子节点的权值,那么我们可以按照y值从大到小依次枚举,枚举该叶子节点是否可以由B的某种策略到达,如果到达了显然答案就是当且枚举的叶子节点的y权值了(因为是从大到小枚举)。

现在考虑一个叶子节点,设为V。V是否可以到达不仅取决于X,还取决于A的心情,X当然想要到达V,因为V是目前为止的最好选择,前面比V好的都无法到达(否则也不会枚举V了。。。),现在问题就是A是否会选择也到达V。设V的x权值为Limit,那么如果A可以到达更好的叶子节点使得其权值大于Limit,A才不会选择V呢,那么现在的关键问题是要保证A无法到达比V还优(对A来说)的叶子节点。我们来定义一个节点是“好的”当且仅当从这个节点出发,无论A怎么转移,X都能使用策略使得A无法到达一个比V更优的叶子节点。否则这个节点称为“坏的”。那么我们可以根据dp来算出每个节点是“好的”还是“坏的”。

对于叶子节点,如果其x值大于Limit,则它是"坏的",否则它是"好的"。

对于非叶子节点,(1)如果它被A控制,且它的后继节点有一个是坏的,则说明A可以到达一个比V更优的节点,说明它是”坏的“。否则A无论如何也只能到达”好的"点,则它是“好的”。

(2)如果它被X控制,且它的后继节点中有一个是“好的”,则说明X可以选择转移到“好的”节点中去,所以它是“好的”,否则它是“坏的”。

那么如果1号节点是"坏的",表示A可以选择一个比V更优的叶子节点,则不能到达V。如果1号节点是“好的”节点,也只能说明X可以用策略使得A无法到达一个比V更优的叶子节点,并不能说明可以到达V。

V能到达的依据为:如果存在一条仅由“好的”点组成的简单路径从1号节点到V,那么说明V可达。

那么这个时候只要从1号节点dfs一遍即可判断。

现在说明一下为什么这样能到达V。因为1号节点是“好的”,说明对于A来说,V是对他来说最优的叶子节点,(其他更优节点已被标为“坏的”,而X是不会让A走到“坏的”节点上去的),同时对X来说,V也是最优节点(前面说过了),那么现在又有一条从1号节点到V的仅由好的节点组成的路径。那么V可达。那么这道题就做完了。

最后说一下X的策略,由上面的分析,可知,如果V可达,X只要告诉A:“对于我所有控制的点,我必然会转移到一个好的后继节点(至于是哪个根据V的选择而定)。即可,这样的话,A只能选择V节点为最优节点了。终于写完了。。。。。

代码如下:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <vector>
#define maxn 210
using namespace std;
struct node{
    int id,A,B;
    node(){}
    node(int x,int y,int z){
        id=x,A=y,B=z;
    }
};
vector<int> e[maxn];
vector<node> vec;
int bel[maxn],A[maxn],B[maxn],dp[maxn][2],vis[maxn];;
bool cmp(const node &x,const node &y){
    return x.B>y.B;
}
void init(int n){
    for(int i=1;i<=n;i++)
    e[i].clear();
}
void dfs1(int now){//cannot make the claim.
    if(dp[now][0]!=-1)//记忆化搜索
    return;
    if(bel[now]==-1){//不属于任何人
        dp[now][0]=A[now];
        dp[now][1]=B[now];
        return;
    }
    for(int i=0;i<e[now].size();i++){
        int v=e[now][i];
        dfs1(v);
        if(bel[now]==0){//属于A
            if(dp[v][0]>dp[now][0]){
                dp[now][0]=dp[v][0];
                dp[now][1]=dp[v][1];
            }
        }
        else{//属于X
            if(dp[v][1]>dp[now][1]){
                dp[now][0]=dp[v][0];
                dp[now][1]=dp[v][1];
            }
        }
    }
}
int dfs2(int now,int limit){//can make the claim
    if(vis[now]!=-1)
    return vis[now];
    if(bel[now]==-1){
        if(A[now]>limit)
        return vis[now]=0;
        return vis[now]=1;
    }
    for(int i=0;i<e[now].size();i++){
        int v=e[now][i];
        dfs2(v,limit);
    }
    for(int i=0;i<e[now].size();i++){
        int v=e[now][i];
        if(bel[now]==0){
            if(!vis[v])
            return vis[now]=0;
        }
        else if(vis[v])
        return vis[now]=1;
    }
    if(bel[now]==0)
    return vis[now]=1;
    return vis[now]=0;
}
int dfs3(int now,int limit){
    if(bel[now]==-1){
        return limit==A[now];
    }
    for(int i=0;i<e[now].size();i++){
        int v=e[now][i];
        if(vis[v]==1&&dfs3(v,limit))
        return 1;
    }
    return 0;
}
int main()
{
   // freopen("dd.txt","r",stdin);
    int ncase,n,num,x;
    char typ[4];
    scanf("%d",&ncase);
    while(ncase--){
        scanf("%d",&n);
        init(n);
        vec.clear();
        memset(bel,-1,sizeof(bel));
        memset(dp,-1,sizeof(dp));
        for(int i=1;i<=n;i++){
            scanf("%d",&num);
            if(num==0){//叶子节点
                scanf("%d%d",&A[i],&B[i]);
                vec.push_back(node(i,A[i],B[i]));
            }
            else{
                for(int j=0;j<num;j++){
                    scanf("%d",&x);
                    e[i].push_back(x);
                }
                scanf("%s",typ);
                if(typ[0]=='A')
                bel[i]=0;
                else
                bel[i]=1;
            }
        }
        dfs1(1);
        int ans1=dp[1][1];
        sort(vec.begin(),vec.end(),cmp);
        int ans2=-1;
        for(int i=0;i<(int)vec.size();i++){//枚举X到达的叶子节点
            memset(vis,-1,sizeof(vis));
            int now=vec[i].id;
            if(dp[now][0]==-1)//若now不能由根节点到达,则跳过
            continue;
            if(dfs2(1,vec[i].A)){
                if(dfs3(1,vec[i].A)){
                    ans2=vec[i].B;
                    break;
                }
            }
        }
        printf("%d %d\n",ans1,ans2);
    }
    return 0;
}



猜你喜欢

转载自blog.csdn.net/dyx404514/article/details/39254179