3143: [Hnoi2013]游走
Description
一个无向连通图,顶点从1编号到N,边从1编号到M。
小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和。
现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小。
Input
第一行是正整数N和M,分别表示该图的顶点数 和边数,接下来M行每行是整数u,v(1≤u,v≤N),表示顶点u与顶点v之间存在一条边。 输入保证30%的数据满足N≤10,100%的数据满足2≤N≤500且是一个无向简单连通图。
Output
仅包含一个实数,表示最小的期望值,保留3位小数。
Sample Input
3 3
2 3
1 2
1 3
Sample Output
3.333
HINT
边(1,2)编号为1,边(1,3)编号2,边(2,3)编号为3。
题解 :dp[ u ] 表示以 u 为出发点的期望次数,s[ v ] 表示 v 点的度, e[ i ] 表示经过第 i 条边的期望次数,edge[ i ] 表示边集。
对于dp[ u ] 我们对每个u 点列一个方程(根据下图的的等式),然后高斯消元得到答案,再计算出对每一条边计算出它的 e[ i ] ,最后贪心一下就得到答案了。
注意精度!!!
#include<iostream>
#include<sstream>
#include<iterator>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<vector>
#include<bitset>
#include<climits>
#include<queue>
#include<iomanip>
#include<cmath>
#include<stack>
#include<map>
#include<ctime>
#include<new>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define MT(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f;
const int O = 1e6;
const int mod = 1e6 + 3;
const int maxn = 5e2 + 5;
const double PI = acos(-1.0);
//const double E = 2.718281828459;
const long double eps = 1e-10;
struct Matrix {
void clear() { for(int i=0; i<maxn; i++) for(int j=0; j<maxn; j++) a[i][j] = 0; }
int equ, var; // equ 表示等式个数,var 表示未知变量个数
long double a[maxn][maxn], x[maxn]; // a表示增广矩阵, x表示解
int GetTriangle() {
int i = 0;
for(int col=0; i<equ && col<var; i++, col++) { // 对第i行进行消元
// 获得最大行,并与第i行交换
long double max_row = fabs(a[i][col]);
int row = i;
for(int k=i+1; k<equ; k++)
if(max_row < fabs(a[k][col])) max_row = fabs(a[row=k][col]);
for(int j=col; j<=var; j++) swap(a[row][j], a[i][j]);
if(fabs(a[i][col]) < eps) { i --; continue; }
// 消元
for(int k=i+1; k<equ; k++) {
if(fabs(a[k][col]) < eps) continue;
long double p = a[k][col] / a[i][col];
for(int j=col; j<=var; j++) a[k][j] -= a[i][j] * p;
}
}
return i;
}
int Gauss(){
int k = GetTriangle();
for(int i=var-1; i>=0; i--) {
long double y = a[i][var];
for(int j=var-1; j>i; j--) y -= x[j] * a[i][j];
x[i] = y / a[i][i];
}
return 0; // 唯一解
}
} M;
struct dd { int to, next; }E[maxn * maxn];
int head[maxn], cnt = 0;
void add(int u, int v) { E[cnt] = {v, head[u]}; head[u] = cnt ++; }
int s[maxn];
pair<int, int>edge[maxn * maxn];
long double e[maxn * maxn];
int main(){
int n, m; scanf("%d%d", &n, &m);
cnt = 0;
for (int i = 0; i < maxn; i++) s[i] = 0, head[i] = -1;
for (int i = 0; i < m; i++) {
int u, v; scanf("%d%d", &u, &v);
s[--u]++; s[--v]++;
add(u, v);
edge[i] = {u, v};
}
M.clear();
M.var = M.equ = n;
for (int u = 0; u < n; u++) {
M.a[u][u] = 1.0;
for (int i = head[u]; ~i; i = E[i].next) {
int v = E[i].to;
M.a[u][v] -= 1.0 / s[v];
M.a[v][u] -= 1.0 / s[u];
}
}
M.a[0][n] = 1.0;
for (int i = 1; i < n; i++) M.a[i][n] = 0.0;
for (int j = 0; j < n; j++) M.a[n - 1][j] = 0.0;
M.a[n - 1][n - 1] = 1.0;
M.Gauss();
for (int i = 0; i < m; i++) {
int u = edge[i].first;
int v = edge[i].second;
e[i] = M.x[u] / s[u] + M.x[v] / s[v];
}
sort(e, e + m);
long double ans = 0;
for (int i = 0; i < m; i++) ans += e[i] * (m - i);
printf("%.3Lf\n", ans);
return 0;
}
最后贪心一下就得到答案了