您的位置:首页 > 其它

ZOJ 3560 Re: the Princess 高斯消元

2014-03-27 10:36 225 查看
题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=25040

题意:一开始女王发了一个帖,然后很多人跟帖,问发帖数的期望。(才发现是princess是公主



解法:首先是字符串处理出g[i][j],表示第j个人的nickname在第i个人的signatures中出现的次数,in[i]表示出了i之外所有人的nickname在i的signatures出现的次数。那么i发了帖之后j跟帖的概率是a[i][j] = 1.0 * g[i][j] / in[i]. 那么整个发帖就可以想像成一个有向图,从i点走向j点的概率是a[i][j],没有路之后停止,问走过的点数的期望。

可以列出方程:

dp[1] = a[1][2] * dp[2] + a[1][3] * dp[3] + a[1][4] * dp[4] + ... + a[1]
* dp[1]
+ 1;

dp[2] = a[2][1] * dp[1] + a[2][3] * dp[3] + a[2][4] * dp[4] + ...+ a[2]
* dp[2]
+ 1;

.......................

可以列出n个方程,一共有n个未知数。果断就是高斯消元解方程了:

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
#define M 1200
#define N 110
const double eps = 1e-8;
int dcmp( double x )
{
return ( x > eps ) - ( x < -eps );
}
char name[110][20], sign[110][M];
char str[M];
int n;

int find( char *str, char *s )
{
int ans = 0;
for( int i = 0; str[i]; ++i ){
int k = 0;
while( str[i+k] && s[k] && str[i+k] == s[k] ) ++k;
if( !s[k] ){
if( str[i+k] >= 'a' && str[i+k] <= 'z' ) continue;
if( i && str[i-1] >= 'a' && str[i-1] <= 'z' ) continue;
++ans;
}
}
return ans;
}
int vis
;
double a

;
int g

, in
;
void dfs( int u )
{
vis[u] = 1;
for( int i = 1; i <= n; ++i ) if( !vis[i] && g[u][i] )
dfs( i );
}
double solve()
{
memset( a, 0, sizeof(a) );
for( int i = 1; i <= n; ++i ){
a[i][i] = a[i][n+1] = -1;
for( int j = 1; j <= n; ++j ) if( g[i][j] )
a[i][j] = 1.0 * g[i][j] / in[i];
}
memset( vis, 0, sizeof(vis) );
dfs( 1 );
for( int i = 1; i <= n; ++i ) if( !vis[i] ){
for( int j = 1; j <= n + 1; ++j ) a[i][j] = 0;
a[i][i] = 1;
}

int k, row = 1, col = 1;
double x;
while( row <= n && col <= n ){
k = row;
while( k <= n && !dcmp( a[k][col] ) ) ++k;
if( k > n ){
++col;
continue;
}
if( k - row )
for( int j = col; j <= n+1; ++j ) swap( a[k][j], a[row][j] );
for( int i = 1; i <= n; ++i ) if( i - row ){
x = a[i][col] / a[row][col];
for( int j = col; j <= n + 1; ++j )
a[i][j] -= x * a[row][j];
}
++row, ++col;
}
k = row;
while( k <= n ){
if( dcmp( a[k][n+1] ) ) return -1;
++k;
}
if( !dcmp( a[1][1] ) ) return -1;
return a[1][n+1] / a[1][1];

}

int main()
{
//freopen( "a.in", "r", stdin );
while( scanf( "%d", &n ) == 1 ){
getchar();
for( int i = 1; i <= n; ++i ){
gets( str );
int j = 0, k = 0;
while( str[j] != ':' )
name[i][j] = str[j], ++j;
name[i][j] = '\0';
++j;
while( str[j] )
sign[i][k++] = str[j++];
sign[i][k] = '\0';
}
memset( in, 0, sizeof(in) );
memset( g, 0, sizeof(g) );
int c;
for( int i = 1; i <= n; ++i )
for( int j = 1; j <= n; ++j ) if( i - j ){
if( c = find( sign[i], name[j] ) )
g[i][j] = c, in[i] += c;
}
double ans = solve();
if( ans < 0 ) printf( "Infinity\n" );
else printf( "%.3lf\n", ans );
}
}


重点我想说的是这个样例:

3

princess: x

a: b

b: a

很多人ac的代码输出的是inf的,我觉得根据题意应该是输出1的。我的代码加了50到54行来把和女王不相关的点去掉:

memset( vis, 0, sizeof(vis) );
dfs( 1 );
for( int i = 1; i <= n; ++i ) if( !vis[i] ){
for( int j = 1; j <= n + 1; ++j ) a[i][j] = 0;
a[i][i] = 1;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: