4215. 【NOIP2015模拟9.12】与机关的决战 (Standard IO)

4215. 【NOIP2015模拟9.12】与机关的决战 (Standard IO)

Time Limits: 1000 ms  Memory Limits: 262144 KB  Detailed Limits  

Description

Lab与机关SERN展开了最后决战。
SERN派出了凶恶的FB,而Labmem们要捕获FB。
FB刚刚在第三水车厂露过行踪,Lab首领冈伦决定倾Lab之力全力追捕FB。
抓捕发生的地点可以表示成一张无向带权图,第三水车厂位于节点1。
冈伦仔细研究了FB的行为模式后得出以下结论:
首先,FB拥有极强的反跟踪能力,因此他深知不走回头路的重要性。他永远不会访问任何一个节点两次。
其次,FB行动以“速”著称,所以FB总是走最短路。亦即,FB访问任何一个节点时,走的路线都是从第三水车厂到该节点的最短路。这里保证从第三水车厂(节点1)到任意节点的最短路唯一。
第三,FB处于不停运动之中。亦即,只要有相邻的节点能满足前两条,他必然会移动。若有多个相邻节点可供选择,他会随机等概率选择一个作为他的移动目标。若没有节点满足这一要求,那么FB会跳世界线。而一旦FB跳世界线,Lab的这次行动很显然就意味着彻底失败。
冈伦分析出以上结论后决定,只能在节点上布置Labmem,实施埋伏抓捕。但是,FB的身体素质、格斗技术都十分优秀。因此,即使FB中伏,也有一定概率逃脱。当然,随着在此地埋伏的Labmem的数目的增多,逃脱几率会减小。如果逃脱成功,FB会像什么都没发生一样,继续按上文所述的原则行动。
注意,FB一旦到达某个节点,埋伏在该处的Labmem会立即行动,只有FB逃脱了当前节点的抓捕后才能进行下一步行动(继续移动或跳世界线),包括节点1,也就是说FB需要先逃脱节点1的埋伏才能进行他的第一次行动。
现在冈伦已经知道各节点设置不同数量的Labmem能成功抓捕FB的概率,现在冈伦想要使得抓捕成功的概率最大。

Input

输入文件第一行包含两个数N,M,分别表示节点数和边数。
接下来M行,每行3个数u,v,w,表示节点u和v之间有一条权值为w的无向边。
接下来一个数S,表示可以参与埋伏的Labmem成员总数。
接下来N行,每行S个数,第i行第j个数Pij表示在节点i埋伏j个Labmem抓捕成功的概率。注意,如果不埋伏任何Labmem,那么显然绝不可能捕获FB。

Output

输出文件仅包含一个实数,保留4位小数,表示最大捕获概率。

Sample Input

4 4
1 2 1
1 3 2
2 4 3
3 4 1
2
0.01 0.1
0.5 0.8
0.5 0.8
0.7 0.9

Sample Output

0.6000

Data Constraint

对于20%的数据,N,S<=6
对于50%的数据,N,S<=30,每个节点度数不大于3
对于100%的数据,N,S<=200,M<=20000,1<=a,b<=N,1<=c<=10000,
0<Pij<=1
无自环、无重边

Source / Author: 常州高级中学 catch

思路:

先把最短路树建出来。

在树上dp。

设f[i][j]为以i为根的子树中选j个Labmem的最大抓捕机率。

对于当前做到的节点i,先处理出它的儿子的f,再将它儿子的状态合并到f[i].(此时默认i节点不放)

最后,枚举i点放几个,转移见标。

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define N 210
#define rint register int 
#define M 40010
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define INF 2147483647
using namespace std;

struct edge
{int v,fr,d;};

int tot,tail[N] ; edge e[M*2];

int n,m,s,i,j,len;
double ans;
int f[N],pre[N],l[N*500],q[N];
double pro[N],g[N][N],P[N][N];




void init()
{
	mem(f,127);
	int i=0,j=1;
	f[1]=0;
	l[1]=1;
	while(i++<j)
	{
		int u=l[i];
		for(int p=tail[u];p;p=e[p].fr)
		{
			int v=e[p].v,d=e[p].d;
			if(f[u] + d < f[v])
			{
				f[v] = f[u] + d;
				pre[v] = u;
				l[++j] = v;
				
			}
		}
	}
	return ;
}



void dfs(int x)
{
	double son=0;
	int i=0,j=0,k=0;
	for(int p=tail[x];p;p=e[p].fr)
		if(pre[e[p].v] == x ) ++son;
//	if(son == 0 )for(j=1;j<=s;j++)g[x][j] = P[x][j];

	for(int p=tail[x];p;p=e[p].fr)
	{
		if(pre[e[p].v] == x)
		{
			int v=e[p].v;
			dfs(v);
			
			//dp(v,x); 
			// v的要乘上1/son 
			
			for(j=s;j>=1;j--) 
			{
				for(k=j;k>0;k--) //x
					g[x][j] = max(g[x][j] , g[x][j-k] + g[v][k]/(double)son );
			}
		}
	}                
	
	for(j=s;j>0;j--)
	{
		for(k=j;k>0;k--)
			g[x][j] = max(g[x][j] , P[x][k] + (1.00-P[x][k]) * g[x][j-k]);
	}
	return ;
}

void add(int u,int v,int d)
{
	e[++tot].v=v;
	e[tot].fr=tail[u];
	e[tot].d=d;
	tail[u]=tot;
}

int main()
{
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)
	{
		int u,v,d;
		scanf("%d%d%d",&u,&v,&d);
		add(u,v,d),add(v,u,d);
	}
	
	scanf("%d",&s);
	for(i=1;i<=n;i++)
		for(j=1;j<=s;j++)scanf("%lf",&P[i][j]);	
	ans=0.00;
	init();// f
	
	mem(g,0);
	dfs(1);
	ans = g[1][s];
	
	printf("%.4lf",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Com_man_der/article/details/89004040