Gym 100015 F Fighting for Triangles 博弈,状压dp
来源:互联网 发布:淘宝五金批发市场 编辑:程序博客网 时间:2024/05/18 00:02
题意 : 有一个三角形架,两个人轮流游戏,每次都可以涂黑一条边,如果涂黑这条边之后恰好凑好了一个小三角形,就可以继续画边,给出初始局势,问在双方都足够理智的情况下,先手胜还是后手胜,或者平局
这种博弈问题,最近见了几道,总的来说是需要做到:
①选择合适的方式记录状态(即局势),且记录的时候要考虑双方的双向性,比如“A吃了三个糖果,B吃了五个糖果”与“A吃了五个糖果,B吃了三个糖果”是两个对称的,不同的局势,一般要记为两种
②可以用dp来记录不同局势下的最优解,同时能做到局面换手
③进行局面转移,可以用dfs来进行搜索,dfs做这个事情很适合,即选择搜索树的临节点
这道题的状态情况比较多,因此用状压dp来做,即18位二进制位,第i位为1,则代表第i条边涂黑了。形成的十进制数记为now
那么就用dp[now][0]记录now所代表的局势下,该先手画边的情形下的最优解,对应的,dp[now][1]是后手的最优解。
用dfs搜索局势,也是依赖于这个题目的规模很小,如果涂了某条边能画出更多的三角形,当前人可以继续画边,因此就表示为
dp[now][state]=max(dp[now][state],dfs(next,state)+add);
这里state表示当前是先手还是后手,next是画了这条边之后的局势,add是当前手画边之后多出来的三角形数目,容易写错的是dfs(next,state)中的state,不用改变
如果不能画出更多的三角形,并不代表这个状态不用遍历了,而是:
dp[now][state]=max(dp[now][state],last-dfs(next,1-state));
用1-state代表局面换手
code:
#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <algorithm>#include <string>#include <map>#include <stack>#include <queue>#include <vector>#define LL long longusing namespace std;const double pi=acos(-1);const int Mod=1e9+7;const double eps=1e-9;int dp[1<<22][2];//store the answer for each statusint vis[1<<22][2];//mark when a state is calculated,and notice that state is bidirectional.int calcu(int n){ int ans=0; bool vis[20]={false}; for(int i=1;i<=18;i++) { if((n>>i)&1)vis[i]=true; } for(int i=0;i<6;i++) { if(vis[i*3+1]&&vis[i*3+2]&&vis[i*3+3]) ans++; } if(vis[3]&&vis[5]&&vis[7])ans++; if(vis[6]&&vis[11]&&vis[13])ans++; if(vis[9]&&vis[14]&&vis[16])ans++; return 9-ans;}int dfs(int now,int state){ if(vis[now][state])return dp[now][state]; int last=calcu(now); vis[now][state]=1; for(int i=1;i<=18;i++) { if(((now>>i)&1)==0)//edge i has not be colored. { int next=now|(1<<i); int tmp=calcu(now)-calcu(next); if(tmp>0) dp[now][state]=max(dp[now][state],dfs(next,state)+tmp); else dp[now][state]=max(dp[now][state],last-dfs(next,1-state)); } } return dp[now][state];}int n;int main(){ //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int now=0; int edge=0; while(cin>>n) { if(n==0)break; now=0; memset(dp,0,sizeof(dp)); memset(vis,0,sizeof(vis)); while(n--) { cin>>edge; now|=(1<<edge); } int last=calcu(now); //cout<<now<<" "<<last<<endl; int numa,numb; numa=dfs(now,0); numb=last-numa; //cout<<numa<<" "<<numb<<endl; if(numa>numb)cout<<"Andy wins"<<endl; else if(numa<numb)cout<<"Ralph wins"<<endl; else cout<<"Draw"<<endl; }}
- Gym 100015 F Fighting for Triangles 博弈,状压dp
- hunnu 11126 Fighting for Triangles
- GYM 101061 F.Fairness(dp)
- Gym 100971C Triangles
- 状压DP Gym
- codeforces GYM 101431E (状态压缩dp+博弈)
- [Gym-101350F] F
- Codeforces Gym 100589F Count Ways(DP+组合数学)
- GYM 100827 F.Knights(dp+矩阵快速幂)
- GYM 101147 F.Bishops Alliance(dp+BIT)
- Codeforces Gym 101190 (NEERC 2016) F. Foreign Postcards (dp + 期望)
- Fighting Spam for Dummies
- HDU Fighting for HDU
- fighting for the future
- Fighting for HDU 2109
- Fighting for HDU
- Fighting for HDU
- HDU2109 Fighting for HDU
- POJ 1064 Cable master(二分-精度)
- [Java开发之路](21)Comparator与Comparable
- Android的四个动画特效
- 蘑菇街2016研发工程师_最大间隔
- POJ2524——Ubiquitous Religions 并查集基础
- Gym 100015 F Fighting for Triangles 博弈,状压dp
- C#入门经典(第6版)
- 利用android提高的的insert,query,update,deleteAPI与execSql,rawQuery函数执行原生的插入,查询,更新,删除语
- java邮件发送--JavaMail
- 从进程和线程定义及区别谈起,包括linux环境下进程和线程的常见函数
- Mysql优化(三)sql语句优化
- iOS - APNS - setApplicationIconBadgeNumber = 0
- 【Usaco2015 dec】High Card Low Card
- android之存储篇_SQLite存储方式 - 一个本科小生的奋斗史 - 博客频道 - CSDN.NET