hdu 4921 Map

Map

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 235    Accepted Submission(s): 74


Problem Description
There are N pieces of fragments, and we’re going to select some of them to form a map. Some fragments can be selected into the map directly (named 1-level fragments), while each of the rest follows  exactly one fragment as its prior fragment. If B follows A and A is an i-level fragment, then B is defined as an (i + 1) - level fragment, and B can be selected only if A has been selected before. Besides, a fragment is followed by at most one other fragment.

Each fragment is assigned with a reliability. The reliability of the whole map is sum up by two parts:
1.The sum of reliabilities of all selected fragments;
2.If there are x i i-level fragments in total and we select y i(y i > 1) fragments among them to form the map, the reliability would increase by  ,where S idenotes the sum of reliabilities of selected fragments in level i.

Please figure out the expectation of reliability of the map under the condition that all valid selections are equiprobable.

At least one fragment should be selected.
 

Input
There are several test cases. The number of test cases T (T<=10) occurs in the first line of input.

For each test case:
The first line consists of two integers N, M (1<=N<=10000,0<=M<N), indicating the number of fragments and relationships respectively.
The second line contains N integers, which describes the reliability of each fragment. The given reliability ranges from 1 to 100, inclusive.
Each of the following M lines contains two integers A and B, which denotes
B follows A(0<=A,B<=N-1).

You may assume that the number of 1-level fragments are no more than 10, and levels will not exceed 1000. No fragment will follow itself directly or indirectly.
 

Output
For each test case, output the expectation with 3 decimal places.
 

Sample Input
  
  
2 2 0 1 2 3 1 1 2 4 1 2
 

Sample Output
  
  
3.000 5.000
Hint
In the first sample, there’re three ways of selections: {0,1}, {0},{1},which respectively generates 6, 1 and 2 of reliability. Hence, the expectation is 3.
 

Author
BUPT
 


这道题目比赛时题意读错了,没看到这句:Besides, a fragment is followed by at most one other fragment.

所以,这题是要求一条条链的和,而不是一棵棵树的和。

因为最多10条链,每条链最多1000层,所以我们可以对每层进行状态压缩求解,复杂度最大为O(1000 * 2 ^10 * 10);

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <functional>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include <ctime>
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF 1e9
#define MAXN 21
const int maxn = 10005;
#define mod 1000000007
#define eps 1e-7
#define pi 3.1415926535897932384626433
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define scan(n) scanf("%d",&n)
#define scanll(n) scanf("%I64d",&n)
#define scan2(n,m) scanf("%d%d",&n,&m)
#define scans(s) scanf("%s",s);
#define ini(a) memset(a,0,sizeof(a))
#define out(n) printf("%d\n",n)
//ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b);}
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
bool vis[maxn]; //标记是否为根节点
int f[11][1001]; // f[i][j]表示的是的i棵树的第j层的节点的编号
int son[maxn]; //son[i]表示i的儿子编号
int level[11]; //level[i]表示的是的i棵树一共用几个节点
int val[maxn]; 
int cnt;
int n,m;
double sum;
void solve()
{
	for(int i = 0;i < 1000; i++)
	{
		int num = 0;
		for(int j = 0;j < cnt; j++) if(f[j][i] != -1) num++;
		if(num == 0) break;
		for(int j = 1;j < (1<<cnt); j++)
		{
			double s = 0,w = 1;
			int y = 0;
			for(int k = 0;k < cnt; k++)
			{
				if(j & (1<<k))
				{
					if(f[k][i] == -1)
					{
						s = 0;
						break;
					}
					s += val[f[k][i]]; //s表示当前这层已选点的和
					w *= level[k] - i; //表示该种选法这些点会被记录几次
					y ++; //当前层已选个数
				}
				else
				{
					w *= min(i,level[k]) + 1;
				}
			}
			sum += s * w;
			if(y > 1) sum += y * s / num * w;
		}
	}
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	//    freopen("out.txt","w",stdout);
#endif  

	int T;
	cin>>T;
	while(T--)
	{
		memset(f,-1,sizeof(f));
		ini(level);
		memset(son, -1, sizeof(son));
		ini(vis);
		scan2(n,m);
		rep(i,n) scan(val[i]);
		int a,b;
		rep(i,m)
		{
			scan2(a,b);
			son[a] = b;
			vis[b] = 1;
		}
		cnt = 0;
		double ways = 1; //一定要为double型,long long保存不下
		for(int i = 0;i < n; i++)
		{
			if(!vis[i])
			{
				int k = 0;
				for(int j = i;j != -1;j = son[j], k++)
				{
					f[cnt][k] = j;
				}
				ways *= k + 1;
				level[cnt] = k;
				cnt++;
			}
		}
		ways -= 1;
	//	cout<<ways<<endl;
		sum = 0;
		solve();

		printf("%.3lf\n",sum / ways);
	}

	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值