列表

详情


NC15138. 图图

描述

先考虑下面这个原始问题:

 给定一个由 N 个点及 M 条有正整数权重的有向边组成的图。点的编号由 0 至 N-1。

 此图中可以有自环 (自己指向自己的边),但是对于任何的有序点对 (a, b),由 a 至 b 的边最多只会有一条。

 在这张图中,有一个旅人,他会按照下列的规则进行移动:如果他所在的点没有任何向外的边,那他就不会移动。如果有恰好一条的对外边,那他就会走到那条对外边所指向的点。如果有超过一条的对外边,那他将会随机选择一条进行移动,每条对外边被选中的概率正比于它的权重。

我们不知道这个旅人现在在哪里,但是我们知道这个旅人现在在这张图中每个点的概率,请问,这个旅人走一步之后,他在这张图中每个点的概率各是多少呢?

蜥蜴觉得这题超级简单,于是很快地写完了一个正确的解答,并且输入原题的样例测试,但是没想到,蜥蜴的程式的输出竟然跟输入一样!也就是说,这个旅人给定的概率分布,跟他走一步之后的概率分布竟然完全一致!蜥蜴觉得这样的测试数据真的太酷了,他也想要产生这样的测试数据,于是,他决定把这个问题交给各位参赛者:对于给定的一张图,请找出一组原题的测试数据,使得原题的答案跟测试数据一致!

输入描述

输入的第一行有两个正整数N, M,分别代表原题中的图的点数及边数。
接下来的M行每行有三个整数a, b, w,分别代表一条a至b的有向边,其权重为w。

输出描述

如果没有这种测试数据存在,请在一行中输出`Impossible`。否则,请输出N行,第i行中有一个浮点数,代表旅人一开始在点i - 1的概率。如果有超过一种可能的答案,输出任意一种皆可。

此题的评审方式如下:

如果答案为`Impossible`,则必须输出`Impossible`才正确。而在有可能答案的测试数据,则不能输出`Impossible`。

浮点数输出的部分,读入后的总和必须和1之间的误差(相对或绝对)不超过10-9,否则评判为错误。

按照蜥蜴原题的代码执行,求得旅人下一步的概率分布,如果对于每个点,下一步的概率跟读入的概率误差(相对或绝对)不超过10-9,则评判为正确,否则为错误。

示例1

输入:

3 3
0 1 1
1 2 1
2 0 1

输出:

0.33333333333333331483
0.33333333333333337034
0.33333333333333331483

示例2

输入:

2 4
0 1 4
0 0 6
1 0 7
1 1 3

输出:

0.63636363636363635354
0.36363636363636364646

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 13ms, 内存消耗: 708K, 提交时间: 2019-08-06 14:45:52

#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;
typedef long long ll;
const int MAXN = 105;
double a[MAXN][MAXN];//增广矩阵
double x[MAXN];//解集
int ans[MAXN];
int p[105];
double isp = 1e-5;
double ispx = 1e-11;
bool ji[105];
int Gauss(int equ, int var) {
	int i, j, k;
	int max_r;// 当前这列绝对值最大的行.
	int col;//当前处理的列
	double ta;
	double temp;
	//转换为阶梯阵.
	col = 0; // 当前处理的列
	for (k = 0; k < equ && col < var; k++, col++) {
		max_r = k;
		for (i = k + 1; i < equ; i++) {
			if (abs(a[i][col]) > abs(a[max_r][col])) max_r = i;
		}
		if (max_r != k) {// 与第k行交换.
			for (j = 0; j < var + 1; j++) swap(a[k][j], a[max_r][j]);
		}
		if (fabs(a[k][col]) <= ispx) {                     
			continue;
		}
		for (int g= 0; g < equ; g++) {
			if (g != k)
			{
				ta = a[g][col] / a[k][col];
				//if (a[i][col] * a[k][col] < 0)ta = -ta;//异号的情况是相加
				for (int j = equ; j >=k; j--) {
					a[g][j] = a[g][j] - a[k][j] * ta;
				}
			}
		}
	}
	return 0;
}
int main(void) {
	int i, j;
	int equ, var;
	scanf("%d%d", &equ, &var);
	memset(a, 0, sizeof(a));
	int x1, y1, val;
	for (j = 0; j < var; j++) {
		scanf("%d%d%d", &x1, &y1, &val);
		ji[y1] = 1;
		a[y1][x1] = 1.0*val;
		ans[x1] += val;
	}
	ll minlcm = 1;
	for (int i = 0; i < equ; i++)
	{
		for (int j = 0; j < equ; j++)
		{
			if (!ans[j])
			{
				a[j][j] = 1;
				ans[j] = 1;
			}
			a[i][j] = a[i][j] / (1.0*ans[j]);
		}
	}
	for (int i = 0; i < equ; i++)
	{
		a[i][i] -= 1;
		a[i][equ] = 0;
	}
	for (int i = 0; i <= equ; i++)
		a[equ][i] = 1;
	int free_num = Gauss(equ + 1, equ);
		if (fabs(a[equ][equ]) > ispx)  free_num= -1;
	if (free_num == -1)puts("Impossible");
	else {
		for (int i = 0; i < equ; i++)
		{
			if (fabs(a[i][equ]) < ispx) printf("%.20lf\n", 0.0);
			else printf("%.20lf\n", a[i][equ] / a[i][i]);
		}
	}
	return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 8ms, 内存消耗: 896K, 提交时间: 2018-02-12 15:46:27

#include <bits/stdc++.h>

using namespace std;
const int N = 205;
const double eps = 1e-12;
int n,g[N][N],sum[N];
double a[N][N],del;

bool gauss()
{
	for(int i=1;i<=n;i++){
		int k=i;
		for(int j=i+1;j<=n+1;j++)if(fabs(a[j][i])>fabs(a[k][i])) k=j;
		if(fabs(del=a[k][i])<eps) continue;
		for(int j=i;j<=n+1;j++)swap(a[i][j],a[k][j]);
		for(int j=i;j<=n+1;j++) a[i][j]/=del;
		for(k=1;k<=n+1;k++)if(k!=i){
			del=a[k][i];
			for(int j=i;j<=n+1;j++)a[k][j]-=del*a[i][j];
		}
	}
	for(int i=1;i<=n;i++){
		if(fabs(a[i][i])<eps&&fabs(a[i][n+1])>eps) return 0;
	}if(fabs(a[n+1][n+1])>eps) return 0;
	return 1;
}
int main()
{
	int m,u,v,w;scanf("%d%d",&n,&m);int chu[N]={0};
	memset(g,0,sizeof(g));memset(sum,0,sizeof(sum));
	for(int i=1;i<=m;i++){scanf("%d%d%d",&u,&v,&w);u++;v++;g[u][v]=w;sum[u]+=w;chu[u]++;}
	for(int i=1;i<N;i++) for(int j=1;j<N;j++) a[i][j]=0.0;
	for(int i=1;i<=n;i++){
		if(chu[i]) for(int j=1;j<=n;j++){if(g[i][j]) a[j][i]+=g[i][j]*1.0/(sum[i]*1.0);}
		else a[i][i]+=1.0;
	}
	for(int i=1;i<=n;i++) a[i][i]-=1.0;
	for(int i=1;i<=n;i++) a[n+1][i]=1.0;a[n+1][n+1]=1.0;
	if(!gauss()) printf("Impossible\n");
	else{
		int flag=1;for(int i=1;i<=n;i++) if(a[i][n+1]<-eps) flag=0;
		if(!flag){printf("Impossible\n");exit(0);}
		for(int i=1;i<=n;i++) if(fabs(a[i][n+1])<eps) a[i][n+1]=0.0;
		for(int i=1;i<=n;i++) printf("%.20lf\n",fabs(a[i][n+1]));
	}
	return 0;
}
/*
5
5
0 1 1
1 2 2
2 3 3
3 4 4
4 0 5
*/

上一题