ZOJ 3560 Re: the Princess 高斯消元

题目链接: 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][n] * dp[1][n] + 1;

dp[2] = a[2][1] * dp[1] + a[2][3] * dp[3] + a[2][4] * dp[4] + ...+ a[2][n] * dp[2][n] + 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[N];
double a[N][N];
int g[N][N], in[N];
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;
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值