考察知识:模拟
算法难度:X+ 实现难度:X+
分析:
把题目读懂之后就比较简单了,直接按题目说明模拟即可
为了简洁,我们用 0...n-1 表示每个小人的位置就可以了
代码:
#include
int n,m,f[100005];//f表示朝向
char name[100005][12];
int main(){
int f_,k;//f_:表示左右
scanf("%d%d",&n,&m);
for(int i=0;i
考察知识:LCA,差分,树链剖分
算法难度:XXXX+ 实现难度:XXXX+
分析:这一定是NOIP有史以来最难的DAY1T2了,甚至比T3还要难。
我不准备介绍我的方法,因为我的方法太长,代码量比较大,思路也比较难表述,所以建议大家参考:P1600题解
考察知识:动态规划,期望
算法难度:XXXX 实现难度:XXX+
分析:这应该是NOIP首次考期望,所以难度主要在算法知识上,如果你不知道期望的基本知识,那基本上没戏了。
对于这道题,我们需要用动态规划解决:
定义状态方程:表示前 i 次课中申请 j 次,需要消耗的最小体力值,其中 k 为 0 时表示第 i 次课没有申请,k为 1 表示第 i 次课申请了。
边界:
状态转移方程:
其中: 分别表示题目中的 ,表示教室 x,y 之间的距离
说明:这个很好推,不解释
说明:对于A 比较好推,对于B:由于第 i-1 节课申请了,所以有 的概率不成功, 概率成功,由期望的概念,我们加权求和就可以了
说明:同理,但是要注意要考虑第 i-1节和 i 节同时申请了的情况,有 4 种情况
代码:
#include
#include
#include
using namespace std;
const int maxn=2005;
int n,m,v,E,a[maxn],b[maxn],d[305][305];
double k[maxn];
double f[maxn][maxn][2];
void solve(){
double ans=20182018.2018;
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
f[i][j][0]=f[i][j][1]=20182018.2018;
f[1][0][0]=f[1][1][1]=0.0;
for(int i=2;i<=n;i++){
int x=a[i-1],y=a[i],x_=b[i-1],y_=b[i];
f[i][0][0]=f[i-1][0][0]+(double)d[x][y];
double d1=(double)d[x][y],
d2=(1-k[i-1])*d[x][y]+d[x_][y]*k[i-1],
d3=k[i]*d[x][y_]+(1-k[i])*d[x][y],
d4=k[i]*k[i-1]*d[x_][y_]+(1-k[i-1])*k[i]*d[x][y_]+k[i-1]*(1-k[i])*d[x_][y]+(1-k[i-1])*(1-k[i])*d[x][y];
for(int j=1;j<=min(i,m);j++){
f[i][j][0]=min(f[i-1][j][0]+d1,f[i-1][j][1]+d2);
f[i][j][1]=min(f[i-1][j-1][0]+d3,f[i-1][j-1][1]+d4);
}
}
for(int i=0;i<=m;i++) ans=min(ans,min(f[n][i][0],f[n][i][1]));
printf("%.2lf\n",ans);
}
void build(){
int u,v_,l;//防止变量重名
memset(d,0x1f,sizeof(d));
scanf("%d%d%d%d",&n,&m,&v,&E);
for(int i=1;i<=n;i++) scanf("%d",a+i);
for(int i=1;i<=n;i++) scanf("%d",b+i);
for(int i=1;i<=n;i++) scanf("%lf",k+i);
for(int i=1;i<=v;i++) d[i][i]=0;
for(int i=1;i<=E;i++){
scanf("%d%d%d",&u,&v_,&l);
d[u][v_]=d[v_][u]=min(d[u][v_],l);
}
for(int K=1;K<=v;K++)//floyd
for(int i=1;i<=v;i++)
for(int j=1;j<=v;j++)
d[i][j]=min(d[i][j],d[i][K]+d[K][j]);
}
int main(){
build();
solve();
return 0;
}