列表

详情


NC17523. [NOI2008]奥运物流

描述

2008 北京奥运会即将开幕,举国上下都在为这一盛事做好准备。为了高效率、成功地举办奥运会,对物流系统进行规划是必不可少的。

物流系统由若干物流基站组成,以1…N 进行编号。每个物流基站i 都有且仅有一个后继基站Si,而可以有多个前驱基站。基站i 中需要继续运输的物资都将被运往后继基站Si,显然一个物流基站的后继基站不能是其本身。编号为1 的物流基站称为控制基站,从任何物流基站都可将物资运往控制基站。注意控制基站也有后继基站,以便在需要时进行物资的流通。在物流系统中,高可靠性与低成 本是主要设计目。对于基站i,我们定义其“可靠性” R(i) 如下:

设物流基站i 有w 个前驱基站P1,P2,...Pw ,即这些基站以i 为后继基站,则基站i 的可靠性R(i)满足下式:

其中Ci 和k 都是常实数且恒为正,且有k 小于1。

整个系统的可靠性与控制基站的可靠性正相关,我们的目标是通过修改物流系统,即更改某些基站的后继基站,使得控制基站的可靠性R(1)尽量 大。但由于经费限制,最多只能修改m 个基站的后继基站,并且,控制基站的后继基站不可被修改。因而我们所面临的问题就是,如何修改不超过m 个基站的后继,使得控制基站的可靠性R(1)最大化。


输入描述

第一行包含两个整数与一个实数,N, m, k。其中N 表示基站数目,m 表示最多可修改的后继基站数目,k 分别为可靠性定义中的常数。

第二行包含N 个整数,分别是S1, S2…SN,即每一个基站的后继基站编号。

第三行包含N 个正实数,分别是C1, C2…CN,为可靠性定义中的常数

输出描述

仅包含一个实数,为可得到的最大R(1)。精确到小数点两位。

示例1

输入:

4 1 0.5
2 3 1 3
10.0 10.0 10.0 10.0

输出:

30.00

说明:

原有物流系统如左图所示,4 个物流基站的可靠性依次为22.8571,21.4286,
25.7143,10。

最优方案为将2 号基站的后继基站改为1 号,如右图所示。 此时4 个基站
的可靠性依次为30,25,15,10。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 425ms, 内存消耗: 1768K, 提交时间: 2019-08-20 21:49:27

#include<bits/stdc++.h>

#define FOG(x,y,z) for(register int x=y,x##_=z;x<=x##_;++x)
#define DOG(x,y,z) for(register int x=y,x##_=z;x>=x##_;--x)
#define FOR(x,y,z) for(int x=y,x##_=z;x<=x##_;++x)
#define DOR(x,y,z) for(int x=y,x##_=z;x>=x##_;--x)
#define FOR_(x,y,z,s) for(int x=y,x##_=z;x<=x##_;x+=s)
#define FOR__(x,y,z) for(int x=y,x##_=z;x<=x##_;x<<=1)
#define EOR(x,y) for(int x##_=head[x],y=edge[x##_].e;x##_;y=edge[x##_=edge[x##_].to].e)
#define EGOR(x,y,z) for(int x##_=head[x],y=edge[x##_].e,z=edge[x##_].c;x##_;y=edge[x##_=edge[x##_].to].e,z=edge[x##_].c)

#define clr(x,y) memset(x,y,sizeof(x))
#define szf(x) sizeof(x)
#define min3(x,y,z) min(min(x,y),z)
#define max3(x,y,z) max(max(x,y),z)

#define read2(x,y) read(x),read(y)
#define read3(x,y,z) read(x),read(y),read(z)
#define read4(x,y,z,w) read3(x,y,z),read(w)
#define reads(str) sf("%s",str)

#define ts (*this)
#define sf scanf
#define pf printf

#define ll long long
#define ull unsigned long long
#define db double
#define ct clock_t
#define ck() clock()
#define rd rand()
#define rmx RAND_MAX
#define RD T*(rd*2-rmx)


using namespace std;

template<class T>bool tomin(T &x,T y){return y<x?x=y,1:0;}
template<class T>bool tomax(T &x,T y){return x<y?x=y,1:0;}
template<class T>void read(T &x){
    char c;
    x=0;
    int f=1;
    while(c=getchar(),c<'0'||c>'9')if(c=='-')f=-1;
    do x=(x<<3)+(x<<1)+(c^48);
    while(c=getchar(),c>='0'&&c<='9');
    x*=f;
}

const db Pi=acos(-1);
const int maxn=65;
int n,m;
int fa[maxn];
db k,c[maxn],K[maxn];
namespace P3{
    struct Edge{
        int e,to;
    }edge[maxn];
    int head[maxn],tot;
    void Add(int x,int y){
        edge[++tot]=(Edge){y,head[x]};
        head[x]=tot;
    }
    db sum;
    void dfs(int u,int f,int dep){
        sum+=c[u]*K[dep++];
        EOR(u,v)if(v!=f&&v!=1)dfs(v,u,dep);
    }
    bool mark[maxn];
    db solve(){
        sum=tot=0;
        FOR(i,1,n)head[i]=mark[i]=0;
        FOR(i,1,n)Add(fa[i],i);
        int x=1,s=0;
        do{
            ++s;
            mark[x]=1;
            x=fa[x];
        }while(!mark[x]);
        if(x!=1)return 0;
        dfs(1,0,0);
        return sum/(1.0-K[s]);
    }
}
namespace P4{
    void solve(){
        db ans=P3::solve();
        FOR(i,2,n)FOR(j,1,n)if(i!=j){
            int tmp=fa[i];
            fa[i]=j;
            tomax(ans,P3::solve());
            fa[i]=tmp;
        }pf("%.2lf",ans);
    }
}
namespace P1{
    db ans;
    void dfs(int u,int s){
        if(!s||u==n+1){
            tomax(ans,P3::solve());
            return;
        }
        dfs(u+1,s);
        FOR(i,1,n)if(i!=fa[u]){
            int tmp=fa[u];
            fa[u]=i;
            dfs(u+1,s-1);
            fa[u]=tmp;
        }
    }
    void solve(){
        dfs(2,m);
        pf("%.2lf",ans);
    }
}
namespace P5{
    int tmp[maxn];
    void solve(){
        db ans=0;
        FOR(i,2,n){
            FOR(j,1,n)tmp[i]=fa[i];
            FOR(j,2,n)if(i!=j)fa[j]=1;
            tomax(ans,P3::solve());
            FOR(j,1,n)fa[i]=tmp[i];
        }pf("%.2lf",ans);
    }
}
namespace P10{
    db dp[maxn][maxn][maxn];
    bool eg[maxn][maxn];
    int D;
    void dfs(int u){
        FOG(d,0,n)FOG(C,0,m)dp[u][C][d]=c[u]*K[d];
        FOG(v,1,n)if(eg[u][v]){
            dfs(v);
            FOG(d,0,n)DOG(c,m,0){
                db res=-(db)1e22;
                FOG(cc,0,c-1)tomax(res,dp[u][cc][d]+dp[v][c-cc-1][1]);
                FOG(cc,0,c)tomax(res,dp[u][cc][d]+dp[v][c-cc][d+1]);
                dp[u][c][d]=res;
            }
        }
        if(u==fa[1])FOG(d,0,n)if(d!=D)FOG(c,0,m)dp[u][c][d]=-(db)1e22;
    }
    void solve(){
        FOG(i,2,n)eg[fa[i]][i]=1;
        db ans=0;
        FOG(d,1,n-1){
            D=d;
            dfs(1);
            db res=0;
            FOG(c,0,m)tomax(res,dp[1][c][0]);
            tomax(ans,res/(1.0-K[d+1]));
        }
        pf("%.2lf",ans);
    }
}
int main(){
    srand(time(NULL));
    read2(n,m);
    sf("%lf",&k);
    K[0]=1;FOR(i,1,n)K[i]=K[i-1]*k;
    FOR(i,1,n)read(fa[i]);
    FOR(i,1,n)sf("%lf",&c[i]);
    if(m==0)pf("%.2lf",P3::solve());
    else if(m==1)P4::solve();
    else if(m==n-2)P5::solve();
    else if(n<=6)P1::solve();
    else P10::solve();
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 744ms, 内存消耗: 2540K, 提交时间: 2019-03-16 15:25:00

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 65;
const double oo = 1e22;
int Nxt[N], to[N], nxt[N], head[N], totE, n, m, Siz[N];
#define Adde(a,b) (to[totE] = b, nxt[totE] = head[a], head[a] = totE++)
double kk[N], dp[N][N][N], C[N], tmp[N][N], k, _MinT;
#define cans(a) ((_MinT = (a)) > ans ? ans = _MinT : 1)

void init() {
    for (int i = 0; i <= n; head[i++] = -1)
      for (int j = 0; j <= n; ++j)
        for (int k = 0; k <= n; ++k)
          dp[i][j][k] = -oo;
    totE = 0;
}

void Cal(int u, int dep) {
    for (int i = 0; i <= Siz[u]; ++i)
      for (int j = 0; j <= m; ++j)
        tmp[i][j] = -oo;
    tmp[0][0] = 0.;
    for (int i = head[u], s = 1; ~i; i = nxt[i], ++s) {
        int v = to[i];
        for (int j = 0; j <= m; ++j)
            for (int k = 0; k <= j; ++k)
                tmp[s][j] = max(tmp[s][j], tmp[s-1][k] + dp[v][j-k][dep]);
            
    }
}

void dfs(int u) {
    Siz[u] = 0;
    for (int i = head[u]; ~i; i = nxt[i], ++Siz[u]) dfs(to[i]);
    Cal(u, 2);
    for (int i = 0; i <= n; ++i)
      for (int j = 1; j <= m; ++j)
        dp[u][j][i] = tmp[Siz[u]][j-1] + C[u] * k;//直接将此站接到1后面

    for (int i = 0; i <= n; ++i) {
        Cal(u, i + 1);
        for (int j = 0; j <= m; ++j)
          dp[u][j][i] = max(dp[u][j][i], tmp[Siz[u]][j] + C[u] * kk[i]);
    }
}

int main() {
    scanf("%d%d%lf", &n, &m, &k);
    for (int i = 1; i <= n; ++i) scanf("%d", Nxt + i);
    for (int i = 1; i <= n; ++i) scanf("%lf", C + i);
    kk[0] = 1; kk[1] = k;
    double ans = -oo;
    for (int i = 2; i < N; ++i) kk[i] = kk[i-1] * k;
    for (int i = Nxt[1], len = 2, j; i ^ 1; i = Nxt[i], ++len) {
        init();
        for (j = 2; j <= n; ++j) 
          if (j ^ i) Adde(Nxt[j], j); else Adde(1, j);
        dfs(1);
        cans(dp[1][m - (Nxt[i] != 1)][0] / (1. - kk[len]));
    }
    printf("%.2lf\n", ans);
    
    return 0;
}

上一题