2280. 最优标号(最小割,位运算)#困难,想不到

活动 - AcWing

给定一个无向图 G=(V,E),每个顶点都有一个标号,它是一个 [0,2^31−1] 内的整数。

不同的顶点可能会有相同的标号。

对每条边 (u,v),我们定义其费用 cost(u,v) 为 u 的标号与 v 的标号的异或值。

现在我们知道一些顶点的标号。

你需要确定余下顶点的标号使得所有边的费用和尽可能小。

输入格式

第一行有两个整数 N,M,N 是图的点数,M 是图的边数。

接下来有 M 行,每行有两个整数 u,v,代表一条连接 u,v 的边。

接下来有一个整数 K,代表已知标号的顶点个数。

接下来的 K 行每行有两个整数 u,p,代表点 u 的标号是 p。

假定这些 u 不会重复。

所有点编号从 1 到 N。

输出格式

输出一行一个整数,即最小的费用和。

数据范围

1≤N≤500,
0≤M≤3000,
1≤K≤N

输入样例:
3 2
1 2
2 3
2
1 5
3 100
输出样例:
97

 解析:

本题给我们一个无向图,然后我们给没有标号的点进行标号,使得所有边的费用和最小。

每条边的费用是两个端点标号的异或和,异或运算是按位运算,因此我们可以每一位单独看,最终的费用和应该是每一位的和加起来。

由于每一位完全独立,因此最终费用和的最小值其实就是求每一位的最小值,再合在一起,就是答案。

由于每一位只有 0 和 1 两种可能,因此所有点可以分成两类,一类是 0,一类是 1。

然后看一下点与点之间的边有哪些情况,0 和 0 之间的边费用就是 0,1 和 1 之间的边费用就是 0,0 和 1 之间的边费用就是 1.

由此可以发现,当两类集合中的点确定之后,整个费用和的最小值就等于两个集合之间的边的数量最小值,也就是割。

假设现在要计算第 k 位,若第 k 位中的两个集合之间的边的最小数量是 m,也就是有 m 个数第 k 位是 1,一个数第 k 位是 1 的费用是 2^k,那么 m 个的费用就是 m⋅2^k 因此如果考虑第 k 位,就是要将所有点的第 k 位分成两类,使得两类之间的边的数量最小,这个问题和流网络中的割非常相似。

我们将原图的无向边都在流网络里建两条有向边。然后我们对点集做一个划分,可以对应到流网络里割的划分。原问题中两个点集之间的边的权值之和就可以对应到两个割之间的割的容量。由于割的容量只会算一个方向,所以权值和也只会算一次,因此原问题中对所有点的划分方式都可以对应到割的划分方式,因此最小费用和就等于最小割(将中间的边的容量设为 1)。

求最小割还需要一个源点和汇点,我们可以建立虚拟源点和虚拟汇点。

有些点最开始是有编号的,如果有些点的标号是 0,说明他一定要和源点在一个集合,那么我们就从源点向这些点连一条容量是 +∞ 的边,这样这些点就一定能从源点走到,这些点就必然不会和汇点在同一个集合,否则源点和汇点就在同一个集合,就矛盾了。如果有些点的标号是 1,说明这些点就必须和汇点在一个集合,同理从这些点向汇点连一条容量是 +∞ 的边。

至于剩下的没有标号的点,有可能和源点一个集合也有可能和汇点一个集合,我们就不做多余的操作了,求最小割的时候按照最优情况分配即可。

综上所述,我们只需要对于每一位分别去求一下最小割,那么每一位的费用就一定是最小的,把每一位的费用加到一块就是总费用的最小值。

本题并没有要求合法方案,这里也可以说明一下,对于每一位,能从源点走到的点都一定和源点在一个集合,能走到汇点的点都一定和汇点在一个集合,通过搜索就能将所有点分成两类,和源点一类的点这一位都选 0,和汇点一类的点这一位都选 1,这样就能确定每个点每一位的值,得出整个的方案。

注意,本题是无向图,无向边我们就建两条有向边即可,但是在残量网络中每条边有一个反向边,一条无向边会变成四条边,这里和前面一样采用合并的方式合成两条边。

作者:小小_88
链接:https://www.acwing.com/solution/content/128199/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

此作者的题解都写得非常好,因此我就直接引用此题解。

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>
#include<sstream>
#include<deque>
#include<unordered_map>
#include<unordered_set>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int N = 5e2 + 5, M = (3e3 + N)*2 + 10, INF = 0x3f3f3f3f;
int n, m, K, S, T;
int h[N], e[M], f[M], ne[M], idx;
int q[N], d[N], cur[N];
int p[N];
struct edge{
	int a, b;
}edges[M];

void add(int a, int b, int c1, int c2) {
	e[idx] = b, f[idx] = c1, ne[idx] = h[a], h[a] = idx++;
	e[idx] = a, f[idx] = c2, ne[idx] = h[b], h[b] = idx++;
}

void build(int x) {
	memset(h, -1, sizeof h);
	idx = 0;
	for (int i = 1; i <= m; i++) {
		add(edges[i].a, edges[i].b, 1, 1);
	}
	for (int i = 1; i <= n; i++) {
		if (p[i] >= 0) {
			if (p[i] >> x & 1)add(i, T, INF, 0);
			else add(S, i, INF, 0);
		}
	}
}

bool bfs() {
	int hh = 0, tt = 0;
	memset(d, -1, sizeof d);
	q[0] = S, d[S] = 0, cur[S] = h[S];
	while (hh <= tt) {
		int t = q[hh++];
		for (int i = h[t]; i != -1; i = ne[i]) {
			int j = e[i];
			if (d[j] == -1 && f[i]) {
				d[j] = d[t] + 1;
				cur[j] = h[j];
				if (j == T)return 1;
				q[++tt] = j;
			}
		}
	}
	return 0;
}

int find(int u, int limit) {
	if (u == T)return limit;
	int flow = 0;
	for (int i = cur[u]; i != -1 && flow < limit; i = ne[i]) {
		int j = e[i];
		cur[u] = i;
		if (d[j] == d[u] + 1 && f[i]) {
			int t = find(j, min(f[i], limit - flow));
			if (!t)d[j] = -1;
			f[i] -= t, f[i ^ 1] += t, flow += t;
		}
	}
	return flow;
}

LL dinic(int x) {
	build(x);
	LL ret = 0, flow;
	while (bfs())while (flow = find(S, INF)) {
		ret += flow;
	}
	return ret;
}

int main() {
	scanf("%d%d", &n, &m);
	S = 0, T = n + 1;
	for (int i = 1, a, b; i <= m; i++) {
		scanf("%d%d", &edges[i].a, &edges[i].b);
	}
	cin >> K;
	memset(p, -1, sizeof p);
	for (int i = 1,a,b; i <= K; i++) {
		scanf("%d%d", &a, &b);
		p[a] = b;
	}
	LL ret = 0;
	for (int i = 0; i <= 30; i++) ret += dinic(i) << i;
	cout << ret << endl;
	return 0;
}

 

import numpy as np import math#用来做计算 X=np.empty(37) #定义一个长度为37的numpy空数组,一维 Y=np.empty(37) #定义一个长度为37的numpy空数组,一维 a=100 i=0 j=0 #还可以再定义一个计数器,用来表示数组的标号 ##############利用循环计算所有要求角度对应的x,y坐标值############## while(i<=360):#注意i表示角度,步长为10 angle=math.radians(i)#把角度转换为弧度 r=a*(1-math.sin(angle)) ##############补充完循环体############## X[j]=r*math.cos(angle) Y[j]=r*math.sin(angle) i=i+10 j=j+1 ##############循环体结束################## X=np.round(X,2) #把X坐标值全部四舍五入保留2位小数,方便结果比 对,调用round函数 Y=np.round(Y,2) #把X坐标值全部四舍五入保留2位小数,方便结果比 对,调用round函数 ########################输出最终的计算结果 ######################## print(&#39;坐标X=&#39;,X) print(&#39;坐标Y=&#39;,Y) import numpy as np X=np.loadtxt("/data/resource/13439063/xdata.txt")#自变量X的数据,数组 Y=np.loadtxt("/data/resource/13439064/ydata.txt")#因变量Y的数据,数组 slope=np.cov(X,Y,ddof=0)[0,1]/np.var(X) #按照最小二乘法的公式计 算斜率 bias=np.mean(Y)-slope*np.mean(X) #按照最小二乘法的公式计算斜率 slope=np.round(slope,2) #四舍五入保留2位小数,方便测评比对,调 用round函数 bias=np.round(bias,2) #四舍五入保留2位小数,方便测评比对,调用 round函数 print(&#39;slope=&#39;,slope,&#39;bias=&#39;,bias)#输出计算得到的模型参数 ########################根据模型参数做预测######################## testX=float(input())#读入测试数据,作为自变量x testY=slope*testX+bias #按照之前得到的模型参数计算因变量y的 值 testX=np.round(testX,2) #四舍五入保留2位小数,方便测评比对, 调用round函数 testY=np.round(testY,2) #四舍五入保留2位小数,方便测评比对, 调用round函数 print(&#39;x=&#39;,testX,&#39;y=&#39;,testY)#输出预测结果 import matplotlib.pyplot as plt import numpy as np #获取训练数据 X = np.loadtxt("/data/resource/13439050/x.txt") #参照X代码,完成Y的读入。#注意:y.txt 文件路径是: /data/resource/13439051/y.txt #begin Y = np.loadtxt("/data/resource/13439051/y.txt") #end #根据最小二乘法计算参数,即斜率和截距 #begin slope = np.cov(X, Y, ddof=0)[0,1] / np.var(X) intercept = np.mean(Y) - slope * np.mean(X) #end #输出训练后得到的参数取值,四舍五入到两位小数 round(slope,2) #begin slope=np.round(slope,2) intercept=np.round(intercept,2) print ( slope ) print ( intercept ) #end #根据计算出的斜率和截距,进行预测 #输入X,预测Y的值 #begin X = float(input()) Y = slope * X + intercept #end #输出Y的预测值,四舍五入到两位小数 #begin Y=round(Y,2) print(Y) #end修改代码的错误并把修稿好的完整代码给我
12-01
由于没有提供具体包含坐标计算、最小二乘法计算斜率和截距、数据读取、预测及绘图等功能的 Python 代码,下面给出一个示例代码,包含了上述功能,并对可能出现的错误进行了处理: ```python import numpy as np import pandas as pd import matplotlib.pyplot as plt from scipy.optimize import curve_fit # 数据读取 try: data = pd.read_excel(&#39;data.xlsx&#39;) # 假设数据存储在 data.xlsx 文件中 X = data[&#39;X&#39;].values Y = data[&#39;Y&#39;].values except FileNotFoundError: print("文件未找到,请检查文件路径和文件名。") # 这里可以使用示例数据 X = np.array([100., 81.38, 61.83, 43.3, 27.36, 15.04, 6.7, 2.06, 0.26, 0., -0.26, -2.06, -6.7, -15.04, -27.36, -43.3, -61.83, -81.38, -100., -115.58, -126.11, -129.9, -125.84, -113.52, -93.3, -66.34, -34.47, 0., 34.47, 66.34, 93.3, 113.52, 125.84, 129.9, 126.11, 115.58, 100.]) Y = np.array([0., 14.35, 22.5, 25., 22.96, 17.92, 11.6, 5.67, 1.5, 0., 1.5, 5.67, 11.6, 17.92, 22.96, 25., 22.5, 14.35, 0., -20.38, -45.9, -75., -105.6, -135.29, -161.6, -182.27, -195.47, -200., -195.47, -182.27, -161.6, -135.29, -105.6, -75., -45.9, -20.38, 0.]) # 最小二乘法计算斜率和截距 def linear_func(x, a, b): return a * x + b try: popt, _ = curve_fit(linear_func, X, Y) slope = popt[0] bias = popt[1] print(f"斜率: {slope}, 截距: {bias}") except RuntimeError: print("最小二乘法拟合失败,请检查数据。") # 预测 while True: user_input = input("请输入一个数字作为自变量 x: ") try: testX = float(user_input) break except ValueError: print("输入无效,请输入一个有效的数字。") testY = slope * testX + bias print(f"对应的因变量 y 值为: {testY}") # 绘图 plt.scatter(X, Y, label=&#39;原始数据&#39;) plt.plot(X, linear_func(X, slope, bias), color=&#39;red&#39;, label=&#39;拟合直线&#39;) plt.scatter(testX, testY, color=&#39;green&#39;, label=&#39;预测点&#39;) plt.title(&#39;数据拟合与预测&#39;, fontsize=16, fontweight=&#39;bold&#39;) plt.xlabel(&#39;X&#39;, fontweight=&#39;bold&#39;) plt.ylabel(&#39;Y&#39;, fontweight=&#39;bold&#39;) plt.legend() plt.show() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值