题解 [美团 CodeM 初赛 Round B] 景区路线规划
有个影响因素k,显然不能高斯消元
n和k都不大,可以直接\(O(nk)\)跑DP
然而带上时间这一影响因素后的转移颇为难写,我从6点直接调到9点最后还是只能dfs爆搜骗了55pts
考场上推方程一定要冷静,调不对再把影响因素都看一遍
我考场上纠结的是\(dp[k][i]\)在什么时候应该继承\(dp[k+1][i]\)
然而考完再看发现根本不需要继承。。。
还是考虑从多个点向一个点转移:
令\(dp[k][i]\)为还剩时间k时,在还剩时间k时经过第i个点次数的期望(实际上就是在第i个点时开心度的期望)
则转移就很显然了:\(dp[k][i] = \sum_{i->v}\frac{1}{cnt[v]}dp[k+c[i]+e.w][v]\)
然而这题还有一个坑点:题里没给边数范围
于是我就默认\(m\leq100\)了 成功RE
应该是不超过\(\frac{N*(N-1)}{2}\)条边
Code:
#include <bits/stdc++.h>
using namespace std;
#define N 110
#define ll long long
//#define int long long
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
struct edge{int to, next, val;}e[N*(N-1)/2];
int n, m, k, K;
int head[N], size, cnt[500][N], c[N];
double dp[500][N], h1[N], h2[N]; // 0->小y 1->妹子
double ans1=0, ans2=0;
inline void add(int s, int t, int w) {edge *k=&e[++size]; k->to=t; k->next=head[s]; k->val=w; head[s]=size;}
int main()
{
#ifdef DEBUG
freopen("1.in", "r", stdin);
#endif
n=read(); m=read(); K=read();
for (int i=1; i<=n; ++i) {c[i]=read(); h1[i]=1.0*read(); h2[i]=1.0*read();}
for (int i=1,u,v,w; i<=m; ++i) {u=read(); v=read(); w=read(); add(u, v, w); add(v, u, w);}
for (int i=1; i<=n; ++i) if (K>=c[i]) dp[K-c[i]][i] = 1.0/n;
for (int k=K-1; k>=0; --k) {
for (int i=1; i<=n; ++i) {
if (k>K-c[i] || !dp[k][i]) continue;
for (int j=head[i],v,t; j; j=e[j].next) {
v=e[j].to; t=k-c[v]-e[j].val;
if (t>=0) ++cnt[k][i];
}
if (cnt[k][i]) {
for (int j=head[i],v,t; j; j=e[j].next) {
v=e[j].to; t=k-c[v]-e[j].val;
if (t>=0) dp[t][v] += dp[k][i]/cnt[k][i];
}
}
//dp[k][i] += dp[k+1][i];
ans1 += dp[k][i]*h1[i];
ans2 += dp[k][i]*h2[i];
}
}
#if 0
for (int k=K; k>=0; --k) {
cout<<setw(2)<<k<<' '; for (int i=1; i<=n; ++i) cout<<setw(4)<<dp[k][i]<<' '; cout<<endl;
cout<<setw(2)<<k<<' '; for (int i=1; i<=n; ++i) cout<<setw(4)<<cnt[k][i]<<' '; cout<<endl;
}
#endif
printf("%.5lf %.5lf\n", ans1, ans2);
return 0;
}