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 */