水题乱刷

【poj2960】 Collecting Bugs

http://poj.org/problem?id=2096 (题目链接)

题意

  有一个程序,其中有s个子结构,每个子结构出bug的概率相等。bug总共分成n类,每种bug出现的概率相等。每天找出一个bug,求所有子结构都出现bug并且每种bug都出现过所需要的期望天数。

Solution

  终于领会了期望dp的一点点。。。

细节

  %.4lf用G++交会Wa。。

代码

// poj2096
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
 
const int maxn=1010;
double f[maxn][maxn];
int n,m;
 
int main() {
    scanf("%d%d",&n,&m);
    f[n][m]=0;
    for (int i=n;i>=0;i--)
        for (int j=m;j>=0;j--) {
            if (i+1<=n) f[i][j]+=f[i+1][j]*(1-(double)i/n)*(double)j/m;
            if (j+1<=m) f[i][j]+=f[i][j+1]*(1-(double)j/m)*(double)i/n;
            if (i+1<=n && j+1<=m) f[i][j]+=f[i+1][j+1]*(1-(double)i/n)*(1-(double)j/m);
            if (i!=n || j!=m) f[i][j]=(f[i][j]+1)/(1-(double)i/n*(double)j/m);
        }
    printf("%.4lf",f[0][0]);
    return 0;
}

【poj3744】 Scout YYF I

http://poj.org/problem?id=3744 (题目链接)

题意

  给出n个雷,分别在 a[1]...a[n] ,走一步概率为 p ,走两步概率为 1-p ,一开始在 1 号位置,问安全到达终点的概率。

Solution

  很显然的dp:f[i]=p*f[i-1]+(1-p)*f[i-2]。考虑a[i]位置上有雷,那么安全通过的概率也就是到达f[a[i]+1]的概率为:f[a[i]-1]*(1-p)。

  因为a[i]很大,所以要分段用矩阵快速幂。

细节

  代码能力下降的厉害。。。莫名Wa了的可以去看看Discuss,好坑。。

代码

// poj3744
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 1<<30
#define eps 1e-8
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
 
double tmp[2][2],f[2][2],t[2][2],p;
int a[20],n;
 
void power(int k) {
    t[0][0]=p,t[0][1]=1,t[1][0]=1-p,t[1][1]=0;
    while (k) {
        if (k&1) {
            for (int i=0;i<=1;i++)
                for (int j=0;j<=1;j++) {
                    tmp[i][j]=0;
                    for (int k=0;k<=1;k++) tmp[i][j]+=f[i][k]*t[k][j];
                }
            memcpy(f,tmp,sizeof(f));
        }
        k>>=1;
        for (int i=0;i<=1;i++)
            for (int j=0;j<=1;j++) {
                tmp[i][j]=0;
                for (int k=0;k<=1;k++) tmp[i][j]+=t[i][k]*t[k][j];
            }
        memcpy(t,tmp,sizeof(t));
    }
}
int main() {
    while (scanf("%d%lf",&n,&p)!=EOF) {
        for (int i=1;i<=n;i++) scanf("%d",&a[i]);
        sort(a+1,a+1+n);a[0]=0;
        f[1][1]=1;
        for (int i=1;i<=n;i++) {
            f[1][0]=f[1][1]*p;
            f[0][1]=f[1][0]*p+f[1][1]*(1-p);
            f[0][0]=f[0][1]*p+f[1][0]*(1-p);
            if (a[i]-a[i-1]==1) {f[1][1]=0;break;}
            else if (a[i]-a[i-1]==2) f[1][1]=f[1][1]*(1-p);
            else if (a[i]-a[i-1]==3) f[1][1]=f[1][0]*(1-p);
            else if (a[i]-a[i-1]==4) f[1][1]=f[0][1]*(1-p);
            else power(a[i]-a[i-1]-5),f[1][1]=(1-p)*f[0][0];
        }
        if (fabs(f[1][1])<eps) puts("0.0000000");
        else printf("%.7lf\n",f[1][1]);
    }
    return 0;
}

【codeforces 148D】 Bag of mice

http://codeforces.com/problemset/problem/148/D (题目链接)

题意

  包中有w个白鼠,b个黑鼠。公主和龙轮流画老鼠,公主先画,谁先画到白鼠谁就赢。龙每画完一只老鼠,就会有另一只老鼠从包中跑出来。每只老鼠被画到以及跑出的概率相等,问公主获胜的概率。

Solution

  令${f_{0/1,i,j}}$表示此时公主/龙选,包中还剩i只白鼠,j只黑鼠,公主赢的概率。那么转移很显然:

$${f_{0,i,j}=\frac{i}{i+j}+\frac{j}{i+j}*f_{1,i,j-1}}$$

$${f_{1,i,j}=\frac{j}{i+j}*(\frac{i}{i+j-1}*f_{0,i-1,j-1}+\frac{j}{i+j-1}*f_{0,i,j-2})}$$

细节

  一个加号没打,看半天没看出来。。

代码

// codeforces148D
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
 
const int maxn=1010;
double f[2][maxn][maxn];
int n,m;
 
int main() {
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) f[0][i][0]=1;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++) {
            f[0][i][j]=(double)(i+j*f[1][i][j-1])/(i+j);
            f[1][i][j]=(double)(i*f[0][i-1][j-1])/(i+j-1);
            if (j>1) f[1][i][j]+=(double)((j-1)*f[0][i][j-2])/(i+j-1);
            f[1][i][j]*=(double)j/(i+j);
        }
    printf("%.9lf",f[0][n][m]);
    return 0;
}

【bzoj1415】 Noi2005—聪聪和可可

http://www.lydsy.com/JudgeOnline/problem.php?id=1415 (题目链接)

题意

  一张图,聪聪想吃可可。每单位时间聪聪可以先移动两次;可可后移动一次或停在原地,它们的概率相等。问聪聪吃到可可的期望时间。

Solution

  先bfs跑出两点间的最短距离。然后记忆化搜索就可以了,很水。。

代码

// bzoj1415
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
 
const int maxn=1010;
struct edge {int to,next;}e[maxn<<1];
int head[maxn],r[maxn],S,T,n,m,cnt;
int dis[maxn][maxn],vis[maxn][maxn];
double f[maxn][maxn];
 
void link(int u,int v) {
    e[++cnt]=(edge){v,head[u]};head[u]=cnt;
    e[++cnt]=(edge){u,head[v]};head[v]=cnt;
}
void bfs(int s,int *d) {
    queue<int> q;q.push(s);
    while (!q.empty()) {
        int x=q.front();q.pop();
        for (int i=head[x];i;i=e[i].next)
            if (!d[e[i].to] && e[i].to!=s) d[e[i].to]=d[x]+1,q.push(e[i].to);
    }
}
double dfs(int s,int t) {
    if (vis[s][t]) return f[s][t];
    if (dis[s][t]==0) return 0;
    if (dis[s][t]<=2) return 1;
    vis[s][t]=f[s][t]=1;
    int k=inf,tmp=s;
    for (int i=head[tmp];i;i=e[i].next)
        if (dis[t][e[i].to]<dis[tmp][t] && e[i].to<k) k=e[i].to;
    tmp=k;k=inf;
    for (int i=head[tmp];i;i=e[i].next)
        if (dis[t][e[i].to]<dis[tmp][t] && e[i].to<k) k=e[i].to;
    tmp=k;
    for (int i=head[t];i;i=e[i].next)
        f[s][t]+=(double)1/(r[t]+1)*dfs(tmp,e[i].to);
    f[s][t]+=(double)1/(r[t]+1)*dfs(tmp,t);
    return f[s][t];
}
int main() {
    scanf("%d%d",&n,&m);
    scanf("%d%d",&S,&T);
    for (int u,v,i=1;i<=m;i++) {
        scanf("%d%d",&u,&v);
        link(u,v);r[u]++;r[v]++;
    }
    for (int i=1;i<=n;i++) bfs(i,dis[i]);
    printf("%.3lf",dfs(S,T));
    return 0;
}

【codeforces 442B】 Andrey and Problem

http://codeforces.com/problemset/problem/442/B (题目链接)

题意

  n个人,每个人有p[i]的概率出一道题。问如何选择其中s个人使得这些人正好只出1道题的概率最大。

Solution

  很显然的概率dp,过了样例即可AC。。话说我为什么要刷B题→_→

代码

// codeforces442B
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
 
const int maxn=200;
double f[maxn][maxn],p[maxn][maxn],a[maxn];
int n;
 
int main() {
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%lf",&a[i]);
    for (int i=1;i<=n;i++) {
        p[i-1][0]=1;
        for (int j=1;j<=i;j++) {
            if (f[i-1][j]<f[i-1][j-1]*(1-a[i])+p[i-1][j-1]*a[i]) {
                f[i][j]=f[i-1][j-1]*(1-a[i])+p[i-1][j-1]*a[i];
                p[i][j]=p[i-1][j-1]*(1-a[i]);
            }
            else f[i][j]=f[i-1][j],p[i][j]=p[i-1][j];
        }
    }
    double ans=0;
    for (int i=1;i<=n;i++) ans=max(ans,f[n][i]);
    printf("%.12lf",ans);
    return 0;
}

【poj3071】 Football

http://poj.org/problem?id=3071 (题目链接)

题意

  ${2^n}$个队伍打淘汰赛,输的被淘汰。第1个队打第2个队,第3个队打第4个队······给出第i个队伍打赢第j个队伍的概率p[i][j],求哪只队伍获得冠军的可能性最大

Solution

  很简单,想到一个dp方程:${f_{i,j}}$表示第i轮,j胜出的概率。转移很显然:

$${f_{i,j}=f_{i-1,j}×f_{i-1,k}×p_{j,k}}$$

代码

// poj3071
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
 
int bin[20],n,m;
double f[1000][1000],p[1000][1000];
 
int main() {
    bin[0]=1;for (int i=1;i<=10;i++) bin[i]=bin[i-1]<<1;
    while (scanf("%d",&n) && n>0) {
        int m=1<<n;
        for (int i=1;i<=m;i++)
            for (int j=1;j<=m;j++) scanf("%lf",&p[i][j]);
        for (int i=1;i<=m;i++) f[0][i]=1;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++) {
                int s=(j-1)/bin[i-1]+1;
                f[i][j]=0;
                if (s&1) {
                    for (int k=s*bin[i-1]+1;k<=(s+1)*bin[i-1];k++)
                        f[i][j]+=f[i-1][j]*f[i-1][k]*p[j][k];
                }
                else {
                    for (int k=(s-2)*bin[i-1]+1;k<=(s-1)*bin[i-1];k++)
                        f[i][j]+=f[i-1][j]*f[i-1][k]*p[j][k];
                }
            }
        int ans=1;
        for (int i=2;i<=m;i++) if (f[n][ans]<f[n][i]) ans=i;
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2017-03-15 09:45  MashiroSky  阅读(232)  评论(0编辑  收藏  举报