2018.7.10比赛

T1

无环图,直接 dp d p 转移即可,从终点往起点转移
由于这道题的数据水,不用考虑无法到达n的路径

#include<bits/stdc++.h>
using namespace std;
int n , m;
int linkk[101000] , t;
int chu[101000];
bool vis[101000];
struct node{
    int n , y , v;
}e[401000];
double dp[101000];
int read(){
    int sum = 0;char c = getchar();bool flag = true;
    while( c < '0' || c > '9' ) {if(c == '-') flag = false;c = getchar();}
    while( c >= '0' && c <= '9' ) sum = sum * 10 + c - 48 , c = getchar();
    if(flag)  return sum;
     else return -sum;
}  
void insert(int x,int y,int z){
    e[++t].y = y;e[t].n = linkk[x];e[t].v = z;chu[x]++;linkk[x] = t;
    return;
}
void init(){
    n = read();m = read();
    for(int i = 1;i <= m;++i){
        int x = read() , y = read() , z = read();
        insert( x , y , z );
    }
    return;
}
void Dp(int x){
    vis[x] = true;
    if(x == n){
        dp[x] = 0;
        return;
    }
    for(int i = linkk[x];i;i = e[i].n){
        int y = e[i].y;
        if(!vis[y]) Dp(y);
        dp[x] = dp[x] + dp[y] + e[i].v;
    }
    if(chu[x])dp[x] /= chu[x];
    return;
}
int main(){
    freopen("tour.in","r",stdin);
    freopen("tour.out","w",stdout); 
    init();
    Dp(1);
    printf("%.2lf",dp[1]);
    return 0;
}
T2

f[i][j] f [ i ] [ j ] 表示剩余 i i j列没有灯的状态到目标状态所需的期望
p[i] p [ i ] 表示行(或列)已经点亮了 i i 行(列),下一次点到所需的行(列)的概率p[i]=i/n
这样就可以写出状态转移方程
f[i][j]=(f[i1][j]+1)p[i](1p[j]) f [ i ] [ j ] = ( f [ i − 1 ] [ j ] + 1 ) ∗ p [ i ] ∗ ( 1 − p [ j ] )
+(f[i][j1]+1)(1p[i])p[j] + ( f [ i ] [ j − 1 ] + 1 ) ∗ ( 1 − p [ i ] ) ∗ p [ j ]
+(f[i1][j1]+1)p[i]p[j] + ( f [ i − 1 ] [ j − 1 ] + 1 ) ∗ p [ i ] ∗ p [ j ]
+(f[i][j]+1)(1p[i])(1p[j]) + ( f [ i ] [ j ] + 1 ) ∗ ( 1 − p [ i ] ) ∗ ( 1 − p [ j ] )
将最后一项包括 f[i][j] f [ i ] [ j ] 的拆开,移项即可求解

#include<bits/stdc++.h>
using namespace std;
double dp[2010][2010];
double p[2010] ;
bool f[2010][2010];
bool xxx[2010] , yyy[2010];
int X , Y;
int n , m;
int read(){
    int sum = 0;char c = getchar();bool flag = true;
    while( c < '0' || c > '9' ) {if(c == '-') flag = false;c = getchar();}
    while( c >= '0' && c <= '9' ) sum = sum * 10 + c - 48 , c = getchar();
    if(flag)  return sum;
     else return -sum;
} 
void init(){
    n = read();int k = read();
    for(int i = 1;i <= k;++i){
        int x = read() , y = read();
        xxx[x] = true;yyy[y] = true;
    }
    for(int i = 1;i <= n;++i)
        p[i] = i * 1.0 / n; 
    return;
}
void Dp(int x,int y){
    if( x < 0 || y < 0 ){
        f[x][y] = true;
        return;
    }

    if( x > 0 && !f[x - 1][y] ) 
        Dp(x - 1 , y);
    if( x > 0 )
        dp[x][y] = dp[x][y] + (dp[x - 1][y] + 1) * p[x] * (1 - p[y]);

    if( y > 0 && !f[x][y - 1]  ) 
        Dp(x , y - 1);
    if( y > 0 ) 
        dp[x][y] = dp[x][y] + (dp[x][y - 1] + 1) * (1 - p[x]) * p[y];

    if( x > 0 && y > 0 && !f[x - 1][y - 1] ) 
        Dp(x - 1 , y - 1);
    if(x > 0 && y > 0)
        dp[x][y] = dp[x][y] + (dp[x - 1][y - 1] + 1) * p[x] * p[y];

    dp[x][y] += (1 - p[x]) * (1 - p[y]);
    dp[x][y] = dp[x][y] / ( 1 - (1 - p[x]) * (1 - p[y]));

    f[x][y] = 1;
    return;
}
void work(){
    X = 0 , Y = 0;
    for(int i = 1;i <= n;++i)
        if(!xxx[i]) X++;
    for(int i = 1;i <= n;++i)
        if(!yyy[i]) Y++;
    dp[0][0] = 0; f[0][0] = true;
    if(!f[X][Y]) Dp(X,Y);
    printf("%.6lf",dp[X][Y]);
    return;
}
int main(){
    freopen("light.in","r",stdin);
    freopen("light.out","w",stdout); 
    init();
    work();
    return 0;
}
T3

传送门:https://blog.csdn.net/a1035719430/article/details/80991529

#include<bits/stdc++.h>
using namespace std;

int n , m;
double p[3010][310] , f[310][3010];
double g[3010] , g_lazy[310] , tmp[3010]; 
double ans;
int num[310];
int read(){
    int sum = 0;char c = getchar();bool flag = true;
    while( c < '0' || c > '9' ) {if(c == '-') flag = false;c = getchar();}
    while( c >= '0' && c <= '9' ) sum = sum * 10 + c - 48 , c = getchar();
    if(flag)  return sum;
     else return -sum;
}  

void pre(){
    n = read();m = read();
    for(int i = 1;i <= n;++i)
        for(int j = 1;j <= m;++j)
            p[i][j] = read() * 1.0 / 1000;
    for(int j = 1;j <= m;++j)
        f[j][0] = 1.0;
    for(int i = 1;i <= m;++i){
        for(int j = 1;j <= n;++j)
            f[i][j] = f[i][j - 1] * ( 1 - p[j][i]);
        g_lazy[i] = 1.0 - f[i][n];
    }
    return;
}

void solve(int x){
    num[x]++;
    if(num[x] >= n){
        g_lazy[x] = 0;
        return;
    }
    for(int i = 0;i <= n;++i)
        tmp[i] = f[x][i];
    f[x][0] = 0.0;
    for(int i = 1;i <= n;++i)
        f[x][i] = f[x][i - 1] * (1.0 - p[i][x]) + tmp[i - 1] * p[i][x];
    g_lazy[x] -= f[x][n];
    return;
}

void work(){
    for(int i = 1;i <= n;++i){
        double Max = 0 ;int id = 0;
        for(int j = 1;j <= m;++j)
            if( Max < g_lazy[j] ){
                Max = g_lazy[j];
                id = j;
            }
        ans += Max;
        if(!id) return;
        solve(id);
    }
    printf("%.8lf",ans);
    return;
}

int main(){
    freopen("gift.in","r",stdin);
    freopen("gift.out","w",stdout); 
    pre();
    work();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值