首页 > 代码库 > hdu 5005 Compromise (2014 ACMICPC regional Anshan Site 1009)
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 edge { int to,next; }e[maxn]; int box[maxn],cnt; void init() { memset(box,-1,sizeof(box)); cnt=0; } void add(int from,int to) { e[cnt].to=to; e[cnt].next=box[from]; box[from]=cnt++; } int bel[maxn],A[maxn],B[maxn]; struct node { int id,A,B; node(){} node(int x,int y,int z) { id=x,A=y,B=z; } }; bool cmp(const node &x,const node &y) { return x.B>y.B; } vector<node> vec; int dp[maxn][2],vis[maxn]; void dfs1(int now) { if(dp[now][0]!=-1) return; if(bel[now]==-1)//不属于任何人 { dp[now][0]=A[now]; dp[now][1]=B[now]; return; } for(int t=box[now];t+1;t=e[t].next) { int v=e[t].to; 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 dfs(int now,int limit) { if(vis[now]!=-1) return vis[now]; if(bel[now]==-1) { if(A[now]>limit) return vis[now]=0; return vis[now]=1; } if(bel[now]==0) { for(int t=box[now];t+1;t=e[t].next) { int v=e[t].to; dfs(v,limit); } for(int t=box[now];t+1;t=e[t].next) { int v=e[t].to; if(!vis[v]) return vis[now]=0; } return vis[now]=1; } else { for(int t=box[now];t+1;t=e[t].next) { int v=e[t].to; dfs(v,limit); } for(int t=box[now];t+1;t=e[t].next) { int v=e[t].to; if(vis[v]) { return vis[now]=1; } } return vis[now]=0; } } bool dfs2(int now,int limit) { if(bel[now]==-1) { if(A[now]==limit) return true; return false; } for(int t=box[now];t+1;t=e[t].next) { int v=e[t].to; if(vis[v]==1) { if(dfs2(v,limit)) return true; } } return false; } int main() { //freopen("dd.txt","r",stdin); int ncase; scanf("%d",&ncase); while(ncase--) { int n; scanf("%d",&n); init(); vec.clear(); memset(bel,-1,sizeof(bel)); memset(dp,-1,sizeof(dp)); for(int i=1;i<=n;i++) { int num; scanf("%d",&num); if(num==0) { scanf("%d%d",&A[i],&B[i]); vec.push_back(node(i,A[i],B[i])); } else { int x; for(int j=0;j<num;j++){ scanf("%d",&x); add(i,x); } char typ[10]; scanf("%s",typ); if(typ[0]=='A') bel[i]=0; else bel[i]=1; } } dfs1(1); int ans1=dp[1][1]; printf("%d ",ans1); sort(vec.begin(),vec.end(),cmp); int ans2=-1; for(int i=0;i<(int)vec.size();i++) { memset(vis,-1,sizeof(vis)); int now=vec[i].id; if(dp[now][0]==-1) continue; if(dfs(1,vec[i].A)) { if(dfs2(1,vec[i].A)) { ans2=vec[i].B; break; } } } printf("%d\n",ans2); } return 0; }
hdu 5005 Compromise (2014 ACMICPC regional Anshan Site 1009)