/**//* 题意:DAG上的博弈,点上有值di,刚开始在X,Y出有白旗、黑旗,每次可以移动一个白/黑旗 起始赌注为1。移动白旗,赌注+=di,黑旗-=di。谁不能移动旗了就输,给对方赌注
用dp[x,y,k]表示白旗在x黑旗在y赌注为k的局面走下去的最大赢钱(可以负数) 记忆化搜索 注意状态是用三维表示,意思是在当前状态下走到结束的最大盈利!! 跟期望很像,都是表示离目标(结束)的代价
而且要算路径条数,需要多一个cnt[x,y,k] */ #include<cstdio> #include<cstring> #include<vector> using namespace std;
const int MAXN = 51; const int INF = 1000000000;
int d[MAXN]; //注意状态的表示是3维的!!x,y,k int dp[MAXN][MAXN][MAXN*4],cnt[MAXN][MAXN][MAXN*4]; vector<int>G[MAXN];
int Memo(int x,int y,int k)//在状态x,y,k下赢得最多的钱 可以是负数 { if(cnt[x][y][100+k]!=-1)return dp[x][y][100+k]; int &ret=dp[x][y][100+k],&ct=cnt[x][y][100+k]; ret = (G[x].empty()&&G[y].empty()?-k:-INF); for(vector<int>::const_iterator it = G[x].begin();it!=G[x].end();it++) { int tmp = -Memo(*it,y,k+d[*it]);//对方赢的钱是Memo(*it,y,k+d[*it]) 当然可以是负数 if(tmp>ret) { ret = tmp; ct = 1; } else if(tmp==ret)ct++;// } for(vector<int>::const_iterator it = G[y].begin();it!=G[y].end();it++) { int tmp = -Memo(x,*it,k-d[*it]); if(tmp>ret) { ret = tmp; ct = 1; } else if(tmp==ret)ct++; } return ret; } int main() { for(int N,M,X,Y;~scanf("%d%d%d%d",&N,&M,&X,&Y);) { for(int i=0;i<N;i++) { scanf("%d",&d[i]); G[i].clear(); } for(int i=1;i<=M;i++) { int u,v; scanf("%d%d",&u,&v); G[u].push_back(v); } memset(cnt,-1,sizeof(cnt)); Memo(X,Y,1); printf("%d %d\n",dp[X][Y][101],cnt[X][Y][101]); } return 0; }
|