CF536D
[[Dijkstra]] [[Game theory]] [[DP]]
link
CF原题
先用dijkstra预处理两个点到所有点的最短距离
然后就能用两个距离来描述一个点了
对于两个最短路相等的点,实际上他们没有差别,可以直接合并
由于两个数表示一个点,可以离散化之后,直接建一个坐标系(一个矩阵)
最大是n*n,n<=2000,可以承受
两人取距离的操作转化为,在这个矩阵上多取几行,和多取几列
然后是一个看上去比较正常的博弈论问题了
这是博弈论!
要从终止状态开始向回转移!
在中间的一个状态,不能贪心向后转移
因为,结束时的情况不清,向后转移有后效性,是不能使当前状态最优化的
由于这是博弈论,所以对手的行为是可以预知的(通过思维嵌套)
所以不管这次做什么决策,对手一定都有一个最优答案
我们需要让下一步不管做什么决策都能知道最终答案,从而来做出最优决策
所以这就告诉我们,必须从终止节点向前递推
设状态 \(f_{i,j,0/1}\) 表示在子矩阵 \(i\to nn,j\to mm\) 中先手(为0或1)能得到的最大得分,0or1为先手的区别在于,第一次取%%的时候%%取列还是行(全局先手为1)
状态转移方程如下:
\[f_{i,j,0}=sum_{i,j}-\max_{k>j~\&\&~ cnt_{i,j}>cnt_{i,k}}f_{i,k,1}
\]
\[f_{i,j,1}=sum_{i,j}-\max_{k>i~\&\&~ cnt_{i,j}>cnt_{k,j}}f_{k,j,0}
\]
当然如果\(cnt_{i,j}==0\),大家都直接赋为0
要后缀 \(\min\) 优化
总时间复杂度 \(\mathcal O(n \log m + n^2)\)
#include<bits/stdc++.h>
using namespace std;
const int N=2003;
int n,m,S,T;
using ll=long long;
using pii=pair<ll,int>;
#define fi first
#define se second
vector<pii>g[N];
priority_queue<pii,vector<pii>,greater<pii>>q;
void Dij(int s,ll*dis){
long long w;int u;
for(int i=1;i<=n;i++)dis[i]=LLONG_MAX;
q.push({dis[s]=0,s});
while(!q.empty())if(tie(w,u)=q.top(),q.pop(),dis[u]==w)for(auto e:g[u])if(dis[e.fi]>w+e.se)q.push({dis[e.fi]=w+e.se,e.fi});
}
int x[N],y[N];
ll b[N],s[N][N],c[N][N],f[N][N][2],col[N],row,cc[N],rc,dis[2][N],va[N];
int main(){
scanf("%d%d%d%d",&n,&m,&S,&T);
for(int i=1;i<=n;i++)scanf("%lld",va+i);
for(ll i=1,a,b,c;i<=m;i++)scanf("%lld%lld%lld",&a,&b,&c),g[a].push_back({b,c}),g[b].push_back({a,c});
Dij(S,dis[0]);
Dij(T,dis[1]);
for(int i=1;i<=n;i++)b[i]=dis[0][i];sort(b+1,b+1+n);int nn=unique(b+1,b+1+n)-b;
for(int i=1;i<=n;i++)x[i]=lower_bound(b+1,b+nn,dis[0][i])-b;
for(int i=1;i<=n;i++)b[i]=dis[1][i];sort(b+1,b+1+n);int mm=unique(b+1,b+1+n)-b;
for(int i=1;i<=n;i++)y[i]=lower_bound(b+1,b+mm,dis[1][i])-b;
for(int i=1;i<=n;i++)s[x[i]][y[i]]+=va[i],c[x[i]][y[i]]=1;
nn--,mm--;
for(int i=nn;i;i--)for(int j=mm;j;j--)c[i][j]+=c[i][j+1],s[i][j]+=s[i][j+1];
for(int j=mm;j;j--)for(int i=nn;i;i--)c[i][j]+=c[i+1][j],s[i][j]+=s[i+1][j];
for(int i=nn;i;i--){
row=rc=0;
for(int j=mm;j;j--){
if(!c[i][j])continue;
if(c[i][j]>c[i][j+1])row=min(row,rc);
if(c[i][j]>c[i+1][j])col[j]=min(cc[j],col[j]);
f[i][j][0]=s[i][j]-row;
f[i][j][1]=s[i][j]-col[j];
rc=min(f[i][j][1],rc);
cc[j]=min(f[i][j][0],cc[j]);
}
}
if(f[1][1][1]<s[1][1]-f[1][1][1])printf("Cry");
else if(f[1][1][1]>s[1][1]-f[1][1][1])printf("Break a heart");
else printf("Flowers");
}

浙公网安备 33010602011771号