[概率期望DP] 2019 南京网络赛 D.Robot 绿豆蛙的归宿

8 篇文章 0 订阅
2 篇文章 0 订阅

绿豆蛙的归宿

https://www.luogu.org/problem/P4316
首先这道题 是在图上dp的一个标准板子题
一般意义上 我们需要每个点的转移方程 但是 这是一个图 所以我们考虑拓扑
同时 每个点连的边数也是需要考虑变成转移系数
这样就有了我们算法进阶指南书上 代码 很好理解
但是 如果当我们甚至 可以停留在原地 或者 有一定概率 直接回到过去的点 的时候 他的写法就不满足 我们更复杂的dp转移的
书上代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
typedef long long ll;

int n, m;
int head[maxn], cnt;
int to[maxn << 1], nxt[maxn << 1], val[maxn << 1];

void ade(int a, int b, int c) {
	to[++ cnt] = b, val[cnt] = c;
	nxt[cnt] = head[a], head[a] = cnt;
}

int out[maxn], deg[maxn];
double dis[maxn];

void topsort() {
	queue<int> que;
	que.push(n);
	while(!que.empty()) {
		int x = que.front(); que.pop();
		for(int i = head[x]; i; i = nxt[i]) {
			int y = to[i];
			dis[y] += (dis[x] + 1.0 * val[i]) / deg[y];
			out[y] --;
			if(out[y] == 0) que.push(y);
		}
	}
}

signed main() {
	scanf("%d %d", &n, &m);
	for(int i = 1, a, b, c; i <= m; ++ i) {
		scanf("%d %d %d", &a, &b, &c);
		ade(b, a, c);
		out[a] ++, deg[a] ++;
	}
	topsort();
	printf("%.2lf\n", dis[1]);
	return 0;
}

以下 是我自己 按照理解写的

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int n, m;
int head[maxn], cnt;
int to[maxn], nxt[maxn];
int from[maxn], pre[maxn], come[maxn], val[maxn], tot;
int out[maxn], deg[maxn];
double dis[maxn];

void cometo(int a, int b, int c) {
    come[++ tot] = b, val[tot] = c;
    pre[tot] = from[a],  from[a] = tot;
}

void ade(int a, int b) {
    to[++ cnt] = b;
    nxt[cnt] = head[a], head[a] = cnt;
}

double redis(int u) {
    if(u == n) return 0;
    double res = 0;
    for(int i = from[u]; i; i = pre[i]) {
        res += (dis[come[i]] + 1.0 * val[i]) / deg[u];
    }
    return res;
}

void topsort() {
    queue<int> que;
    que.push(n);
    while(!que.empty()) {
        int x = que.front(); que.pop();
        dis[x] = redis(x);
        for(int i = head[x]; i; i = nxt[i]) {
            out[to[i]] --;
            if(out[to[i]] == 0) que.push(to[i]);
        }
    }
}

int main() {
    scanf("%d %d", &n, &m);
    for(int i = 1, a, b, c; i <= m; ++ i) {
        scanf("%d %d %d", &a, &b, &c);
        cometo(a, b, c), ade(b, a);
        deg[a] ++, out[a] ++;
    }
    topsort();
    printf("%.2lf\n", dis[1]);
    return 0;
}

2019南京网络赛 D. Robot

首先是推公式了 如果你理解了上面的题 这个公式很简单推出
不过这里 我们天数是我们的消耗 每次走都是 不同的 所以我们先得求一个点天数期望
在去 算 损耗期望
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
typedef long long ll;

int n, m;
int head[maxn], cnt;
int to[maxn], nxt[maxn];

int pre[maxn], come[maxn], from[maxn], tot;
int out[maxn], deg[maxn], out2[maxn];
double dis[maxn], ans[maxn];

void cometo(int a, int b) {
    out[a] ++, out2[a] ++, deg[a] ++;
    pre[++ tot] = from[a], from[a] = tot, come[tot] = b;
}

void ade(int a, int b) {
	to[++ cnt] = b;
	nxt[cnt] = head[a], head[a] = cnt;
}

double redays(int u) {
    if(u == n) return 0;
    double res = 0;
    for(int i = from[u]; i; i = pre[i]) 
        res += dis[come[i]];
    return (res + deg[u] + 1) / deg[u];
}

void topsort1() {
	queue<int> que;
	que.push(n);
	while(!que.empty()) {
		int x = que.front(); que.pop();
        dis[x] = redays(x);
        for(int i = head[x]; i; i = nxt[i]) {
            int y = to[i];
            out[y] --;
            if(out[y] == 0) que.push(y);
        }
	}
}

double recon(int u) {
    if(u == n) return 0;
    double res = 0;
    for(int i = from[u]; i; i = pre[i]) 
        res += ans[come[i]] + dis[u];
    return (res + dis[u]) / deg[u];
}
queue<int> que;
void topsort2() {
	que.push(n);
	while(!que.empty()) {
		int x = que.front(); que.pop();
        ans[x] = recon(x);
        for(int i = head[x]; i; i = nxt[i]) {
            int y = to[i];
            out2[y] --;
            if(out2[y] == 0) que.push(y);
        }
	}
}

signed main() {
	int cas;
	scanf("%d" ,&cas);
	while(cas --) {
		scanf("%d %d", &n, &m);
		memset(head, 0, (n + 5) * sizeof(int));
        memset(dis, 0, (n + 5) * sizeof(int));
        memset(ans, 0, (n + 5) * sizeof(int));
        memset(out2, 0, (n + 5) * sizeof(int));
        memset(deg, 0, (n + 5) * sizeof(int));
        memset(from, 0, (n + 5) * sizeof(int));
		cnt = 0, tot = 0;
		for(int i = 1, a, b; i <= m; i ++) {
			scanf("%d %d", &a, &b);
			cometo(a, b), ade(b, a);
		}
		topsort1();
		topsort2();
		printf("%.2lf\n", ans[1]);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值