CSP/NOIP新赛制内部挑战赛1 B. 逆转时间

 

 

 

 

 

 

 

 

 

 考虑部分分数

sub 2

a都是0,也就是说不存在回溯的情况,所以就是普通的期望dp
用f[i]表示i-n的期望距离 f[u]=sum{f[v]}/size
期望得分:30pts

代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int cnt,n,m,k,head[maxn];
struct edge
{
    int to,nxt,v;
}e[maxn<<1];
double f[maxn];
void add(int x,int y,int z)
{
    e[++cnt].to=y;
    e[cnt].nxt=head[x];
    e[cnt].v=z;
    head[x]=cnt;
}
int in[maxn],out[maxn];
queue <int> q;
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    int x,y,z;
    for(int i=1;i<=n;i++) scanf("%d",&x);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        in[x]++; out[x]++; add(y,x,z);    
    }
    q.push(n);
    out[n]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        f[u]/=out[u];
        for(int i=head[u];i;i=e[i].nxt)
        {
            int to=e[i].to;
            f[to]+=f[u]+e[i].v;
            in[to]--;
            if(!in[to]) q.push(to);
        }
    }
    printf("%.7lf",f[1]);
    return 0;
}

 

sub 3

a[1]=1 也就是一直都可以回溯,就已经和正解做法差不多了,就不单独写实现了



正解

 先跑一次拓扑序,然后找到路径

之后在对于每个点,去计算dp值,dp[u][0/1]表示这个点是否能回溯时的期望距离

 

 

还因为有的double开成了int而WA了两发

 

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const double inf=1e17;
int cnt,n,m,k,head[maxn],a[maxn];
struct edge
{
    int to,nxt,v;
}e[maxn<<1];
double dp[maxn][2];
void add(int x,int y,int z)
{
    e[++cnt].to=y;
    e[cnt].nxt=head[x];
    e[cnt].v=z;
    head[x]=cnt;
}
int in[maxn],out[maxn],path[maxn],tot;
queue <int> q;
void toposort()
{
    for(int i=1;i<=n;i++)
        if(!in[i]) q.push(i);
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        path[++tot]=u;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int to=e[i].to;
            in[to]--;
            if(!in[to]) q.push(to);
        }
    }
}
double ss[maxn];
void calc(int x,int flag)
{
    int siz=0,top=0;
    double res=0;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int to=e[i].to;
        int fl=flag|a[to];
        if(fl) ss[++top]=dp[to][fl];
        res+=dp[to][fl]+e[i].v;
        siz++;
    }
    if(!siz) return;
    sort(ss+1,ss+top+1);
    reverse(ss+1,ss+top+1);
    double ans=res/siz;
    for(int i=1;i<=top;i++)
    {
        res-=ss[i];
        if(siz<=i) break;
        ans=min(ans,(double)1.0*res/(siz-i)+(double)1.0*i*k/(siz-i));
    }
    dp[x][flag]=min(ans,dp[x][flag]);
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    int x,y,z;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        in[y]++; add(x,y,z);    
    }
    toposort();
    for(int i=1;i<n;i++)
        dp[i][0]=inf,dp[i][1]=inf;
    for(int i=n;i>=1;i--)
    {
        int u=path[i];
        calc(u,0); calc(u,1);    
    }
    printf("%0.7lf",dp[1][a[1]]);
    return 0;
}

 

这是一道期望(树形的)dp,这个内容还需要多加练习啊!

 

 




posted @ 2020-11-26 11:13  andyc_03  阅读(108)  评论(0编辑  收藏  举报