 /**//*
題意: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;
}

|