noip2018信心赛day2 重要程度

28 篇文章 0 订阅
15 篇文章 0 订阅

2.重要程度
Description
为了正确开导lyh,也为了警示后人,指导老师进行了严肃而又激情的讲说。
人的一生会遇到 个特殊事件(比如:初赛没过和谈恋爱)。事件之间肯定是有联系的,而且是双向的(参考上述 例子)。简单的说, 个事件构成了一个有 条边的无向联通图。
直接讲述重要性可能会使某些人难以接受(继续参考上述例子)。为了比较科学一点,我们设 为事件 的重要 程度,有 I(x)=∑C(s,t,x)/C(s,t)
其中,C(s,t) 表示s 到t 的最短路径的数目,而 C(s,t,x)表示s 到t 的最短路径中经过 x的路径数目。因为是无向连通 图,所以一定存在至少一条最短路径,即每个事件的重要程度一定有意义。
由于计算量较大,为了避免尴尬,你要及时说出所有事件的重要程度。
Input
输入文件为
第一行两个整数 和 ,表示总事件数和事件构成连通图的边数,事件按 到 编号。
接下来 行,每行三个整数 , 和 。表示一条连接 , ,权值为 的无向边。
Output
输出文件为
输出共 行,每行一个实数,精确到小数点后三位。第 行表示 。
Sample Input
4 4 1 2 1
2 3 1 3 4 1 4 1 1 Sample Output
1.000
1.000 1.000 1.000
对于1号结点而言,只有2号到4号结点和4号到2号结点的最短路经过1号结点,而2号结点和4号结点之间的最短路 又有2条。因而根据定义,1号结点的重要程度计算为1/2+1/2=1。由于图的对称性,其他三个结点的重要程度也都 是1。
Data Constraint
对于50%数据,n<=10 , 对于100%数据, n<=100,

分析:spfa求出每对点之间的最短路径数量G[i][j],那么C(i,j,x)=G[i][x]*G[x][j]。

代码

#include <cstdio>
#include <queue>
#define N 105
#define ll long long
#define inf 1e15
using namespace std;

struct arr
{
	int to,nxt;
	ll w;
}a[N * N];
ll f[N][N],g[N][N][N],G[N][N];
int n,m,l,ls[N * N];
bool vis[N];
queue<int> q;

void spfa(int s)
{
	for (int i = 1; i <= n; i++)
	{
		vis[i] = false;
		f[s][i] = inf;
	}
	while (q.size()) q.pop();
	f[s][s] = 0;
	G[s][s] = 1;
	q.push(s);
	while (q.size())
	{
		int u = q.front();
		q.pop();
		vis[u] = false;
		for (int i = ls[u]; i; i = a[i].nxt)
		{
			int v = a[i].to;
			if (f[s][u] + a[i].w < f[s][v])
			{
				f[s][v] = f[s][u] + a[i].w;
				G[s][v] = G[s][u];
				if (!vis[v])
				{
					vis[v] = true;
					q.push(v);
				}
			}
			else if (f[s][u] + a[i].w == f[s][v])
				G[s][v] += G[s][u];
		}
	}
}

void add(int x, int y, ll w)
{
	a[++l].to = y;
	a[l].w = w;
	a[l].nxt = ls[x];
	ls[x] = l;
}

int main()
{
	freopen("importance.in","r",stdin);
	freopen("importance.out","w",stdout);
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++) f[i][j] = inf;
	for (int i = 1; i <= m; i++)
	{
		int x, y;
		ll w;
		scanf("%d%d%lld", &x, &y, &w);
		add(x, y, w);
		add(y, x, w);
	}
	for (int i = 1; i <= n; i++) spfa(i);
	for (int k = 1; k <= n; k++)
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				if (i != j && j != k && i != k)
					if (f[i][k] + f[k][j] == f[i][j])
						g[i][j][k]= G[i][k] * G[k][j];
	for (int k = 1; k <= n; k++)
	{
		double ans = 0;
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				if (i != j && i != k && j != k)
					ans += ((1.0 * g[i][j][k]) / (1.0 * G[i][j]));
		printf("%.3lf\n", ans);
	}
	fclose(stdin);
	fclose(stdout);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值