1. 程式人生 > 資訊 >內蒙古國資委:嚴肅查處整治虛擬貨幣“挖礦”活動

內蒙古國資委:嚴肅查處整治虛擬貨幣“挖礦”活動

link

emm,題目本身並不見得很難,主要是有一個點必須理清楚。期望DP的計算需要遵守全期望公式,大概是\(E=\sum\limits_i^m p_i\times c_i\),也就是說你在搞清楚一個東西對於期望的貢獻的同時還應該要知道它產生貢獻的概率。這也就回答了為什麼本題中只能逆推而不能順推的問題。畢竟一個點要走到終點必須也只能經過它的某條出邊,所以經過某條出邊的概率是一定的;而順推時,你要從某條入邊到當前點的概率為來點被經過的概率再除以來點的出度,顯然要麻煩一些。但第二種也並不是不能寫,可以考慮對期望貢獻進行拆分,計算每條邊被貢獻的概率,遞推時只用計算經過某個點的概率即可。於是就產生了兩種寫法:

第一種逆推:

#include<cstdio>
#include<queue>
#include<iostream>
//#define zczc
using namespace std;
const int N=200010;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}
int m,n,s1,s2,s3,d[N],s[N],a[N],cnt;
struct edge{int t,v,next;}e[N];
int head[N],esum;
inline void add(int fr,int to,int val){
	esum++;e[esum].t=to;
	e[esum].v=val;e[esum].next=head[fr];head[fr]=esum;
}
queue<int>q;
double f[N]={0};
signed main(){
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	read(m);read(n);
	for(int i=1;i<=n;i++){
		read(s1);read(s2);read(s3);
		add(s1,s2,s3);d[s2]++,s[s1]++;
	}
	for(int i=1;i<=m;i++)
		if(d[i]==0)q.push(i);
	while(!q.empty()){
		int now=q.front();q.pop();a[++cnt]=now;
		for(int i=head[now];i;i=e[i].next){
			if(--d[e[i].t]==0)q.push(e[i].t);
		}
	}
	f[m]=0;
	for(int i=m-1;i;i--){
		int wh=a[i];
		for(int j=head[wh];j;j=e[j].next){
			f[wh]+=(double)(f[e[j].t]+e[j].v)/s[wh];
		}
	}
	printf("%.2f",f[1]);
	return 0;
}

第二種貢獻拆分:

#include<cstdio>
#include<queue>
#include<iostream>
//#define zczc
using namespace std;
const int N=200010;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}

int m,n,s1,s2,s3,d[N],s[N],a[N],cnt;
struct edge{
	int t,v,next;
}e[N];
int head[N],esum;
inline void add(int fr,int to,int val){
	esum++;
	e[esum].t=to;
	e[esum].v=val; 
	e[esum].next=head[fr];
	head[fr]=esum;
	return;
}

queue<int>q;
double f[N]={0},ans=0;

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);read(n);
	for(int i=1;i<=n;i++){
		read(s1);read(s2);read(s3);
		add(s1,s2,s3);d[s2]++;s[s1]++;
	}
	for(int i=1;i<=m;i++)if(d[i]==0)q.push(i);
	f[1]=1;
	while(!q.empty()){
		int now=q.front();q.pop();
		if(now==m)break;
		for(int i=head[now];i;i=e[i].next){
			f[e[i].t]+=f[now]/s[now];
			ans+=e[i].v*f[now]/s[now];
			if(--d[e[i].t]==0)q.push(e[i].t);
		}
	}
	printf("%.2f",ans);
	
	return 0;
}

這道黃題對於圖上期望DP具有借鑑意義(吧)。

一如既往,萬事勝意