列表

详情


NC20086. [HNOI2011]XOR和路径

描述

给定一个无向连通图,其节点编号为 1 到 N,其边的权值为非负整数。试求出一条从 1 号节点到 N 号节点的路径,使得该路径上经过的边的权值的“XOR 和”最大。该路径可以重复经过某些节点或边,当一条边在路径中出现多次时,其权值在计算“XOR 和”时也要被重复计算相应多的次数。

直接求解上述问题比较困难,于是你决定使用非完美算法。具体来说,从 1 号节点开始,以相等的概率,随机选择与当前节点相关联的某条边,并沿这条边走到下一个节点,重复这个过程,直到走到 N 号节点为止,便得到一条从 1 号节点到 N 号节点的路径。显然得到每条这样的路径的概率是不同的并且每条这样的路径的“XOR 和”也不一样。现在请你求出该算法得到的路径的“XOR 和”的期望值。


输入描述

从文件input.txt中读入数据,输入文件的第一行是用空格隔开的两个正整数N和M,分别表示该图的节点数和边数。
紧接着的M行,每行是用空格隔开的三个非负整数u,v和w(1≤u,v≤N,0≤w≤109),表示该图的一条边(u,v),其权值为w。
输入的数据保证图连通,30%的数据满足N≤30,100%的数据满足2≤N≤100,M≤10000,但是图中可能有重边或自环。

输出描述

输出文件 output.txt 仅包含一个实数,表示上述算法得到的路径的“XOR 和”的期望值,要求保留三位小数。(建议使用精度较高的数据类型进行计算)

示例1

输入:

2 2
1 1 2
1 2 3

输出:

2.333

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 19ms, 内存消耗: 700K, 提交时间: 2020-08-06 22:46:01

//Author:XuHt
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 106;
int n, m;
double a[N][N], b[N], ans;
vector<pair<int, int> > e[N];

void work() {
	for (int i = 1; i < n; i++) {
		int now = i;
		for (int j = i + 1; j < n; j++)
			if (fabs(a[j][i]) > fabs(a[now][i])) now = j;
		for (int j = 0; j <= n; j++) swap(a[i][j], a[now][j]);
		for (int j = i + 1; j <= n; j++) {
			double rate = a[j][i] / a[i][i];
			for (int k = 0; k <= n; k++) a[j][k] = a[i][k] * rate - a[j][k];
		}
	}
	for (int i = n; i; i--) {
		for (int j = i + 1; j <= n; j++) a[i][0] -= a[i][j] * b[j];
		b[i] = a[i][0] / a[i][i];
	}
}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		int x, y, z;
		scanf("%d %d %d", &x, &y, &z);
		e[x].push_back(make_pair(y, z));
		if (x != y) e[y].push_back(make_pair(x, z));
	}
	for (int i = 0; i < 31; i++) {
		memset(a, 0, sizeof(a));
		memset(b, 0, sizeof(b));
		for (int x = 1; x <= n; x++) a[x][x] = 1;
		for (int x = 1; x < n; x++) {
			int s = e[x].size();
			for (int j = 0; j < s; j++) {
				int y = e[x][j].first, z = e[x][j].second;
				double w = 1.0 / s;
				if ((z >> i) & 1) {
					a[x][y] += w;
					a[x][0] += w;
				} else a[x][y] -= w;
			}
		}
		work();
		ans += b[1] * (1 << i);
	}
	printf("%.3f\n", ans);
	return 0;
}

C++ 解法, 执行用时: 16ms, 内存消耗: 664K, 提交时间: 2022-02-08 11:15:43

#include<bits/stdc++.h>
using namespace std;
int n,m,hd[101],cnt,d[101],p[101]={1},u,v,w;
double a[101][101],f[101],ans;
struct ee{int to,nt,w;}e[20001];
void add(int u,int v,int w){e[++cnt].to=v;e[cnt].w=w;e[cnt].nt=hd[u];hd[u]=cnt;d[v]++;}
void gs(){
    for(int i=1;i<n;i++)for(int j=i+1;j<=n;j++){double tmp=a[j][i]/a[i][i];for(int k=1;k<n+2;k++)a[j][k]-=a[i][k]*tmp;}
    for(int i=n;i;i--){f[i]=a[i][n+1]/a[i][i];for(int j=i-1;j;j--)a[j][n+1]-=a[j][i]*f[i];}
}
int main(){
	cin>>n>>m;
	memset(hd,-1,sizeof hd);
    for(int i=1;i<31;i++)p[i]=p[i-1]*2;
    for(int i=1;i<=m;i++){cin>>u>>v>>w;add(u,v,w);if(u-v)add(v,u,w);}
    for(int i=0;i<31;i++){
        memset(a,0,sizeof(a));
		a[n][n]--;
        for(int u=1;u<n;u++){
            a[u][u]=-1;
            for(int j=hd[u];j+1;j=e[j].nt){int v=e[j].to;if(~e[j].w&p[i])a[u][v]+=1.0/d[u];else a[u][n+1]-=1.0/d[u],a[u][v]-=1.0/d[u];}
        }
        gs();
        ans+=f[1]*p[i];
    }
    printf("%.3lf",ans);
    return 0;
}

上一题