EOJ Monthly 2017.12 - F1. 不见了的人口数据 (Easy) (高斯消元)

F1. 不见了的人口数据 (Easy)

Time limit per test: 1.0 seconds

Memory limit: 256 megabytes

星光镇的地图是有  n  个点, n1  条路,这些点从  1  到  n  编号,两两之间都可达;这  n1  条路的长度都是  1

这  n  个点是居民聚居点,第  i  个点上有  ai  个居民。去年的时候,星光镇政府曾经做了个人口普查,他们投入了大量的资金,获知了所有节点的  ai ,而获知的目的,就是为新政府大楼的选址做准备的。由于新政府大楼一定会建在一个居民聚居点上,所以星光镇政府求出了对于每个聚居点  j  的「政府大楼收益评估函数」:

pj=i=1ndis(i,j)ai

其中  dis(i,j)  是  i,j  号点之间的最短距离。特别的, dis(i,i)=0

新政府大楼造好了,政府自然而然地进行了一些证据销毁工作,同时「一不小心」销毁了重金得来的人口普查数据:也就是说  ai  都丢失了。但是巧的是,所有的收益评估函数值  p1,p2,,pn  竟然都留存了下来。星光镇数据研究所唐纳德博士表示:「从这些函数值中,我们完全可以将所有的人口数据都反求出来。」但是唐纳德博士,虽然是一个著名的数学天才,但却很有可能是一个假博士,他这话自然不能当真。所以当星光镇政府又要造一个新的政府大楼,又要用到这些人口数据时,他们花费了巨资进行再调查。

身在异国的你听到此事后大笑不止,利用  p1,p2,,pn  轻轻松松地求出了  a1,a2,a3,,an

Input

输入具有如下形式:

nu1 v1un1 vn1p1 p2  pn1 pn

第一行一个整数  n

接下来  n1  行,每行两个整数  ui,vi  ( 1ui,vin ),分别表示这  n1  条路。这  n1  条路都可以双向通行。两个居民聚居点之间不会有多条路相连,也不会有一条路的两端连接了同一个居民聚居点。

最后一行,用空格隔开的  n  个整数  p1,p2,,pn ,表示收益评估函数。

数据保证答案有解,并且满足  0a1,a2,,an1 000

数据规模约定:

  • 对于 Easy 档: 1n100
  • 对于 Hard 档: 1n250 000

Output

依次序输出  a1,a2,,an 。如果有多解,输出任意解。

Examples

input
2
1 2
11 9
output
9 11
input
6
1 2
1 3
3 4
3 5
5 6
32 45 19 28 16 21
output
0 1 2 3 4 5

因为easy题数据小,可以解方程做。

高斯消元模板拉kuangbin。

注意精度,卡了一万次。

(但我觉得解法肯定不是这样做的,但我菜啊


#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
#define LL long long
#define eps 1e-8
const int maxn=1000;
double a[maxn][maxn],x[maxn];//方程的左边的矩阵和等式右边的值,求解之后x存的就是结果
int equ,var;//方程数和未知数个数
int Gauss()
{
	int i,j,k,col,max_r;
	for(k=0,col=0;k<equ&&col<var;k++,col++) {
		max_r=k;
		for(i=k+1;i<equ;i++)
			if(fabs(a[i][col])>fabs(a[max_r][col]))
				max_r=i;
		if(fabs(a[max_r][col])<eps)
			return 0;
		if(k!=max_r) {
			for(j=col;j<var;j++)
				swap(a[k][j],a[max_r][j]);
			swap(x[k],x[max_r]);
		}
		x[k]/=a[k][col];
		for(j=col+1;j<var;j++)
			a[k][j]/=a[k][col];
		a[k][col]=1;
		for(i=0;i<equ;i++)
			if(i!=k) {
				x[i]-=x[k]*a[i][k];
				for(j=col+1;j<var;j++)
					a[i][j]-=a[k][j]*a[i][col];
				a[i][col]=0;
			}

	}
	return 1;

}
int head[maxn],nxt[maxn],sz=0,to[maxn];

void add(int u,int v)
{
	nxt[sz]=head[u];
	to[sz]=v;
	head[u]=sz++;
}
void dfs(int u,int pre,double now,int x)
{
	a[x][u]=now;
	for(int i=head[u];~i;i=nxt[i]){
		int v=to[i];
		if(v==pre) continue;
		dfs(v,u,now+1,x);
	}
}
int main()
{
	for(int i=0;i<=111;i++) head[i]=-1;
	memset(a,0,sizeof a);
	memset(x,0,sizeof x);
	sz=0;
	int n;
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d %d",&u,&v);
		u--;
		v--;
		add(u,v);
		add(v,u);
	}
	for(int i=0;i<n;i++){
		double p;scanf("%lf",&p);
		x[i]=p;
	}
	for(int i=0;i<n;i++){
		dfs(i,-1,0,i);
	}
	equ=n;
	var=n;
	Gauss();
	for(int i=0;i<n;i++){
		for(int k=0;k<=1000;k++){
			if(fabs(x[i]-k)<eps){
				printf("%d%c",k,i==n-1?'\n':' ');
			}
		}
	}

}







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值