BZOJ1916[USACO 2010 Open Gold 2.Water Slides]——DP+记忆化搜索
题目描述
受到秘鲁的马丘比丘的新式水上乐园的启发,Farmer John决定也为奶牛们建 一个水上乐园。当然,它最大的亮点就是新奇巨大的水上冲浪。超级轨道包含 E (1 <= E <=150,000)条小轨道连接着V (V <= 50,000)个水池,编号为1..V。每个小轨道必须按照特定的方向运行,不能够反向运行。奶牛们从1号水池出发,经过若干条小轨道,最终到达V号水池。每个水池(除了V号和1号之外,都有至少一条小轨道进来和一条小轨道出去,并且,一头奶牛从任何一个水池到达V 号水池。最后,由于这是一个冲浪,从任何一个水池出发都不可能回到这个水池) 每条小轨道从水池P_i到水池Q_i (1 <= P_i <= V; 1<= Q_i <= V; P_i != Q_i), 轨道有一个开心值F_i (0 <= F_i <= 2,000,000,000),Bessie总的开心值就是经过的所有轨道的开心值之和。Bessie自然希望越开心越好,并且,她有足够长的时间在轨道上玩。因此,她精心地挑选路线。但是,由于她是头奶牛,所以,会有至多K (1 <= K <= 10)次的情况,她无法控制,并且随机从某个水池选择了一条轨道(这种情况甚至会在1号水池发生) 如果Bessie选择了在最坏情况下,最大化她的开心值,那么,她在这种情况下一次冲浪可以得到的最大开心值是多少? 在样例中,考虑一个超级轨道,包含了3个水池(在图中用括号表示)和4条小轨道,K的值为1 (开心值在括号外表示出来,用箭头标识) 她总是从1号水池出发,抵达3号水池。如果她总是可以自己选择,就是不会发生不能控制的情况她可以选择从1到2(这条轨道开心值为5),再从2到3(开心值为5),总的开心值为5+5=10。但是,如过她在1号水池失去控制,直接到了3,那么开心值为9,如果她在2号水池失去控制,她总的开心值为8。Bessie想要找到最大化开心值的方案,可以直接从1到3,这样,如果在1号水池失去控制,这样,她就不会在2号水池失去控制了,就能够得到10的开心值。因此,她的开心值至少为9
输入
* 第一行: 三个用空格隔开的整数: V, E, 和 K * 第2到第E+1行: 第i+1行包含三个用空格隔开的整数: P_i, Q_i, and F_i
输出
* 第一样: 一行一个整数表示在最坏情况下最大化的开心值
样例输入
3 4 1
2 3 5
1 2 5
1 3 9
2 3 3
2 3 5
1 2 5
1 3 9
2 3 3
样例输出
9
首先说一下问题的意思:“在最坏情况下最大化的开心值”就是指你想使她的开心值最小,但她想使开心值最大的最优策略。但你想阻止她的方法只有在k个节点阻止她走最长路方向,却不能指定她走哪条路。对于样例,最长路是从1到2再到3,长度为5+5=10。如果你在1节点阻止她,那她只能直接走到3,长度为9;如果你在2阻止她,并不是说她走到2再被阻止,走了长度为3的路,而是直接放弃走2,直接走到3,长度还是9。所以她至少获得的开心值是9。从1走到n等价于从n走到1,所以我们不妨倒着来做(正推比较麻烦但也可行),定义f[i][j]表示走到i节点还剩j次失误的最优解,最终结果就是f[1][0];f[x][j]=min(max(f[from[i]][j]+val[i]),min(f[from[i]][j-1]+val[i])),其中from[i]表示能直接到达x的一个点。从1节点记忆化搜索即可。
最后附上代码。
#include<queue> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int head[50010]; int to[150010]; int next[150010]; long long val[150010]; int n,m,k; int x,y; long long v; int tot; long long f[50010][16]; long long INF=1ll<<60; void add(int x,int y,long long v) { tot++; next[tot]=head[x]; head[x]=tot; to[tot]=y; val[tot]=v; } long long dfs(int x,int y) { if(f[x][y]!=INF) { return f[x][y]; } long long ma=0ll; long long mi=INF; for(int i=head[x];i;i=next[i]) { ma=max(ma,dfs(to[i],y)+val[i]); if(y+1<=k) { mi=min(mi,dfs(to[i],y+1)+val[i]); } } return f[x][y]=min(mi,ma); } int main() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=m;i++) { scanf("%d%d%lld",&x,&y,&v); add(x,y,v); } for(int i=1;i<=n;i++) { for(int j=0;j<=k;j++) { if(i!=n) { f[i][j]=INF; } else { f[i][j]=0; } } } printf("%lld",dfs(1,0)); }