草庐IT

二分图(概念、相关算法和题目应用)(全面整理)

阐上 2024-04-28 原文

TP

二分图的概念:

二分图通常针对 无向图 问题(有些题目虽然是有向图,但一样有二分图性质)

在一张图中,如果能够把全部的点分到 两个集合 中,保证两个集合内部没有 任何边 ,图中的边 只存在于两个集合之间,这张图就是二分图
——————————————————————————————————————————

二分图常用算法:

染色法(判断一个图是否为二分图):

算法原理就是,用 黑 与 白 这两种颜色对图中点染色(相当于给点归属一个集合),一个点显然不能同时具有两种颜色,若有,此图就不是二分图



代码:

bool dfs(int u, int c) {
	color[u] = c;//当前点先染色
	for (int i = h[u]; ~i; i = ne[i]) {
		int j = e[i];//对于这个点连接的所有的点
		if (color[j]) {//如果已经被染过色了
			if (color[j] == c)return false;
			//就需要判断一下,如果两点颜色一样,染色就冲突了
		}
		else if (!dfs(j, 3 - c))return false;
		//否则dfs去染下一个结点,赋予的颜色肯定要跟 c 不一样
		//3 - 1 == 2,3 - 2 == 1
		//同时传回染色成功与否的信息
	}
	return true;
}

bool check() {
	memset(color, 0, sizeof color);//0 —— 未染色,1 —— 黑色,2 —— 白色
	for (int i = 1; i <= n; i++)
		if (color[i] == 0)//一旦某个点没染过色,dfs去染色
			if (!dfs(i, 1))return false;//如果传回false显然失败,此图不是二分图
	return true;
	//否则true
}

遍历了这张图的点和边,时间复杂度 O ( n + m ) O(n + m) O(n+)

——————————————————————————————————————————

匈牙利算法(求出二分图的最大匹配数):

满足 是二分图 这个前提,才能使用匈牙利算法

所谓 最大匹配数 的意思就是:

两个集合分别选一个点,这两个点之间有边就确认一段关系(一个集合中的两点 占有 另一集合中同一个点 是不合法的 一夫一妻(确信) ),最多的关系数量就是这张二分图的最大匹配

代码:

bool find(int x) { //标准匈牙利
	for (int j = 1; j <= n; j++)
		if (!st[j] && g[x][j]) { 
		//x 点连向的所有点(因为是二分图,所以这些点都在右集合),如果存在边且没标记过
			st[j] = true;
			//标记一下,防止多次遍历
			int t = match[j];
			//右集合中该点的匹配对象

			if (!t || find(t)) { 
			//没对象就可以和 x 匹配,有的话就让 t 尝试更改对象,能更改就和 x 匹配,不能就false
				match[j] = x;
				return true;
			}
		}
	return false;
}

int main() {
	cin >> n;
	int ans = 0;
	for (int i = 1; i <= n; i++) { //遍历左集合
		memset(st, 0, sizeof st);//每次都要重置标记
		if (find(i))ans++;//一旦有一个匹配,数量就++
	}
	cout << ans;

	return 0;
}

最坏情况会每个点遍历全部边一次,所以时间复杂度是 O ( n m ) O(nm) O(nm)

但匈牙利算法还是很优秀的,大部分情况时间都比较小

如果想要更优秀的算法左转 网络流 吧,匈牙利匹配本质上还是网络流的一种特殊形式,网络流可以更好地解决此类问题。网络流真是太简单了bushi

——————————————————————————————————————————

相应题目应用:

二分图 染色 应用:

Acwing:关押罪犯


题意又臭又长,总结就是:

尽可能将 仇恨值大的 两名罪犯放在不同监狱中

把仇恨值当作罪犯之间的边的边权,两座监狱看作两个集合

这道题就变成了 如何让二分图 两集合之间的边权 尽可能大(使得集合内部边权尽可能小,冲突也就没那么激烈)

观察数据范围,此题可以用 二分 + 染色法 求解

代码:

#include<bits/stdc++.h>
#include<unordered_set>
#include<unordered_map>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define sca scanf
#define pri printf
#define ul (u << 1)
#define ur (u << 1 | 1)
#define fx first
#define fy second
//#pragma GCC optimize(2)
//[博客地址](https://blog.csdn.net/weixin_51797626?t=1) 
using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

const int N = 20010, M = 200010, MM = 3000010;
int INF = 0x3f3f3f3f, mod = 100003;
ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k, T, S, D;
int h[N], e[M], ne[M], w[M], idx;
int color[N];//染色,记录该点的状态:0 —— 未染色、1 —— 染白、2 —— 染黑

void add(int a, int b, int x) {
	e[idx] = b, w[idx] = x, ne[idx] = h[a], h[a] = idx++;
}

bool dfs(int u, int c, int mid) {
	color[u] = c;//染该点
	for (int i = h[u]; ~i; i = ne[i]) {
		int j = e[i];
		if (w[i] <= mid)continue;
		//mid是答案,是设定的集合内部最大边权,如果该边小于等mid,边两点显然可以随意处理,放在一个集合内也行

		//否则,该边两点就严格要放在两个不同集合,防止冲突

		if (color[j]) { //连向的点若被染过色
			if (color[j] == c)return false;//显然色不能相同
		}
		else if (!dfs(j, 3 - c, mid))return false;//没被染过就染该点
	}
	return true;//成功
}

bool check(int mid) {
	mem(color, 0);//每次重新对点染色
	for (int i = 1; i <= n; i++)
		if (color[i] == 0)//枚举每一个点是因为有可能有多个连通块
			if (!dfs(i, 1, mid))return false;//要保证都为二分图
	return true;
}

int main() {
	cinios;

	cin >> n >> m;
	mem(h, -1);
	for (int i = 0; i < m; i++) {
		int a, b, x;
		cin >> a >> b >> x;
		add(a, b, x);//二分图通常针对的都是无向图
		add(b, a, x);
	}

	int l = 0, r = 1e9;//二分答案
	while (l < r)
	{
		int mid = l + r >> 1;//mid 即是最小的最大影响力
		//比 mid 小的影响显然都可以随意塞到监狱中
		//比 mid 大的影响要让其尽可能不存在(即一边两点分别在图的两个不同子集中)
		//也就是询问能否用比 mid 大的边建立一个二分图

		if (check(mid))r = mid;//能的话显然包含答案
		else l = mid + 1;//不能就要增大,右移往答案靠拢
	}

	cout << l;

	return 0;
}

——————————————————————————————————————————

二分图最大匹配应用:

Acwing:棋盘覆盖


看上去像状压dp,但一看数据范围 2 100 2^{100} 2100状压肯定炸,所以探讨一下是否具有二分图的性质

如果把每个格子看成点,放置骨牌(长2宽1)的操作可以看成 两点之间连一条边

那每个格子能放置骨牌就有四种情况四个方向连四条边(除非另一个格子被禁止放置)

每个格子都这样处理,可以得到一张图

可以发现的是,能放置最多骨牌 == 能不重复尽可能多地选取边 == 最大匹配数量

之前说过,求最大匹配的前提是这张图是二分图,所以我们需要判断下这张图是否具有二分图的性质

纸上作画一下便可发现,奇数格/偶数格 彼此之间是没有边的(相当于二分图中的两个集合)

因此,
代码:

#include<bits/stdc++.h>
#include<unordered_set>
#include<unordered_map>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define sca scanf
#define pri printf
#define ul (u << 1)
#define ur (u << 1 | 1)
#define fx first
#define fy second
//#pragma GCC optimize(2)
//[博客地址](https://blog.csdn.net/weixin_51797626?t=1) 
using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

const int N = 110, M = 50010, MM = 3000010;
int INF = 0x3f3f3f3f, mod = 100003;
ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k, T, S, D;
bool g[N][N], st[N][N];
PII match[N][N];
int dx[] = { -1,0,1,0 }, dy[] = { 0,1,0,-1 };

//防止长2宽1的骨牌,可以看作是在相邻两格之间建边(要求合法)
//结果要求最多能放多少块骨牌,就相当于 “ 最多有多少条匹配边 ”
//经过观察象棋棋盘上黑白格的分布,我们可以推导出,N行N列的棋盘具有二分图性质
//至此,该问题就变成了一个二分图最大匹配求解问题

int find(int x, int y) { //匈牙利算法
	for (int i = 0; i < 4; i++) { //每个点的边指向都确定了,所以可以不建边
		int a = x + dx[i], b = y + dy[i];

		if (a <= 0 || b <= 0 || a > n || b > n || g[a][b])continue;
		//越界或者触碰禁止的格子就不处理

		PII t = match[a][b];
		if (st[t.fx][t.fy])continue;//防止多次遍历
		st[t.fx][t.fy] = true;

		if (t.fx == 0 || find(t.fx, t.fy)) { //一旦该点没被标记过,或者点曾经的对象可以找到下家
			match[a][b] = { x,y };
			return true;//该点就能匹配

			//搜索时是遍历左子集往右子集的边,但match记录的是右子集点的对象
		}
	}
	return false;
}

int main() {
	cinios;

	cin >> n >> m;

	while (m--)
	{
		int a, b;
		cin >> a >> b;
		g[a][b] = true;//点数较小,用邻接矩阵存储方便
	}

	int ans = 0;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			if (i + j & 1 && !g[i][j]) { //只对集合一半的点处理匹配,同时不能是障碍
				mem(st, 0);//每次要重置标记
				if (find(i, j))ans++;//匹配成功++
			}

	cout << ans;

	return 0;
}

同类型题

洛谷:矩阵游戏


洛谷题解就挺好

目的是使得最终(1,1)(2,2)…(n,n)都有一个点

可以看作为,最终状态需要每 i 行和 i 列都存在一个匹配

建图方式:对于 i 行 j 列的1点,建一条 i 连向 j 的边即可,最后跑一个二分图匹配,只有匹配数为 n 才能说明有解

可以证明交换行、交换列的操作不会影响匹配数

代码:

#include<bits/stdc++.h>
#include<unordered_set>
#include<unordered_map>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define sca scanf
#define pri printf
#define ul (u << 1)
#define ur (u << 1 | 1)
#define fx first
#define fy second
//#pragma GCC optimize(2)
//[博客地址](https://blog.csdn.net/weixin_51797626?t=1) 
using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

const int N = 210, M = 40010, MM = 3000010;
int INF = 0x3f3f3f3f, mod = 100003;
ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k, T, S, D;
int h[N], e[M], ne[M], idx;
int match[N << 1];
bool st[N << 1];

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

bool find(int x) { //标准匈牙利
	for (int i = h[x]; ~i; i = ne[i]) {
		int j = e[i];
		if (st[j])continue;
		st[j] = true;

		if (!match[j] || find(match[j])) {
			match[j] = x;
			return true;
		}
	}
	return false;
}

int main() {
	cinios;

	cin >> T;
	while (T--)
	{
		cin >> n;
		mem(h, -1);
		idx = 0;

		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++) {
				cin >> k;
				if (k)add(i, n + j);//行对列建边
				//虽然二分图是无向图问题,但只用建单向边即可,枚举其中一个集合
			}

		mem(match, 0);
		int mat = 0;
		for (int i = 1; i <= n; i++) {
			mem(st, 0);
			if (find(i))mat++;
		}

		if (mat == n)cout << "Yes";//匹配数必须为 n
		else cout << "No";
		cout << '\n';
	}

	return 0;
}

——————————————————————————————————————————

二分图最大匹配的一些推论:

由最大匹配推导而来,本文不细节探讨证明(我也不会啊

——————————————————————————————————————————

二分图最小点覆盖应用:

证明可得:二分图的最大匹配数 == 最小点覆盖(证明理解不能,寄了)

什么是最小点覆盖?

最小点覆盖并不只在二分图中才存在

在一个图中任意选取 最少 多少个点(两个集合中都可以选!),可以保证图中 所有的边都与选取的点相连

这个数量就是最小点覆盖

Acwing:机械任务


代码:

#include<bits/stdc++.h>
#include<unordered_set>
#include<unordered_map>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define sca scanf
#define pri printf
#define ul (u << 1)
#define ur (u << 1 | 1)
#define fx first
#define fy second
//#pragma GCC optimize(2)
//[博客地址](https://blog.csdn.net/weixin_51797626?t=1) 
using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

const int N = 110, M = 400010, MM = 3000010;
int INF = 0x3f3f3f3f, mod = 100003;
ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k, T, S, D;
int match[N];
bool st[N], g[N][N];

//证明可得:二分图的最大匹配数 == 最小点覆盖(证明理解不能,寄了)

//什么是最小点覆盖?
//最小点覆盖并不只在二分图中才存在,任意一个图中
//选取 最少 多少个点,可以保证图中 所有的边都与选取的点相连
//这个数量就是最小点覆盖

bool find(int x) { //标准匈牙利
	for (int i = 1; i < m; i++)
		if (!st[i] && g[x][i]) { //确保有边
			st[i] = true;
			int t = match[i];
			if (t == 0 || find(t)) {
				match[i] = x;
				return true;
			}
		}
	return false;
}

int main() {
	cinios;

	//该题就可以转化成一个最小点覆盖问题,然后用二分图最大匹配求解

	//对于每一个任务 i,可以选择(A 的 a[i] 模式)或(B 的 b[i] 模式)解决
	//
	//所以在 a[i] 和 b[i] 之间建一条边,代表任务 i(这样的图显然是二分图)
	//要完成所有任务显然表示要 选取所有的边
	// 
	//这个问题就可以转化成:最少标记多少个点,即在 a[i] 与 b[i] 中选择其中一个,可以保证图中所有的边都与选取的点相连

	while (cin >> n, n)
	{
		cin >> m >> k;
		mem(g, 0);
		mem(match, 0);

		while (k--)
		{
			int t, a, b;
			cin >> t >> a >> b;
			if (!a || !b)continue;//0模式初始就能解决
			g[a][b] = true;//无向图,但建单向边就可以find了
		}

		int ans = 0;
		for (int i = 1; i < n; i++) {
			mem(st, 0);
			if (find(i))ans++;
		}
			
		cout << ans << '\n';
	}

	return 0;
}

同类型题

思维上更巧妙的最小点覆盖应用

Acwing:泥地


代码:

#include<bits/stdc++.h>
#include<unordered_set>
#include<unordered_map>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define sca scanf
#define pri printf
#define ul (u << 1)
#define ur (u << 1 | 1)
#define fx first
#define fy second
//#pragma GCC optimize(2)
//[博客地址](https://blog.csdn.net/weixin_51797626?t=1) 
using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

const int N = 2010, M = 500010, MM = 3000010;
int INF = 0x3f3f3f3f, mod = 100003;
ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k, T, S, D;
int match[N], r[N][N], c[N][N], rcnt = 1, ccnt = 1;
//记录每个点所在的泥地连续行、连续列,行对列连边,集合自然分为行集合、列集合,满足二分图性质
//最后求的就是,最少的点覆盖所有的边,即最小点覆盖
bool st[N], g[N][N];
string s[60];
//注意一下数组大小

bool find(int x) { //标准匈牙利
	for (int j = 1; j <= ccnt; j++)
		if (!st[j] && g[x][j]) {
			st[j] = true;
			int t = match[j];

			if (!t || find(t)) {
				match[j] = x;
				return true;
			}
		}
	return false;
}

int main() {
	cinios;

	cin >> n >> m;
	for (int i = 0; i < n; i++)
		cin >> s[i];

	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (j && s[i][j] == '*' && s[i][j - 1] == '.')rcnt++;
			//一旦遇到干净地面,泥地行编号++
			if (s[i][j] == '*')r[i][j] = rcnt;//赋予该格行编号
		}
		rcnt++;//换行也要++
	}

	//对列同样操作,小心bug
	for (int i = 0; i < m; i++) { //bug —— i < n, j < m
		for (int j = 0; j < n; j++) {
			if (j && s[j][i] == '*' && s[j - 1][i] == '.')ccnt++;
			//bug —— s[j][i - 1]
			if (s[j][i] == '*')c[j][i] = ccnt;//bug —— c[i][j]
		}
		ccnt++;
	}

	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			if (s[i][j] == '*') //对于泥地格,建边
				g[r[i][j]][c[i][j]] = true;

	int ans = 0;
	for (int i = 1; i <= rcnt; i++) { //行集合匹配列集合
		mem(st, 0);
		if (find(i))ans++;
	}
	cout << ans;

	return 0;
}

——————————————————————————————————————————

二分图最大独立集应用:

最大独立集 是一个点数,指在一个图中选取最多多少个点,可以使得这些点所组成的集合 内部任意两点间没有边

最大独立集 ==(总点数 - 最小点覆盖)

Acwing:骑士放置


代码:

#include<bits/stdc++.h>
#include<unordered_set>
#include<unordered_map>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define sca scanf
#define pri printf
#define ul (u << 1)
#define ur (u << 1 | 1)
#define fx first
#define fy second
//#pragma GCC optimize(2)
//[博客地址](https://blog.csdn.net/weixin_51797626?t=1) 
using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

const int N = 110, M = 10010, MM = 3000010;
int INF = 0x3f3f3f3f, mod = 100003;
ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k, T, S, D;
PII match[N][N];
bool st[N][N], g[N][N];
int dx[] = { -1,1,2,2,1,-1,-2,-2 }, dy[] = { 2,2,1,-1,-2,-2,-1,1 };

//最大匹配数 == 最小点覆盖 == 总点数 - 最大独立集
// 
//什么是最大独立集?最大独立集 是一个点数,指在一个图中选取最多多少个点,可以使得这些点所组成的集合 内部任意两点间没有边
//
//因此显然,当你把一个图中 最小点覆盖集合 中的点删去(最少的点覆盖所有的边),剩下的点组成的集合就是 最大独立集(总点数 - 最小点覆盖)

//该题问最多能放多少个不能互相攻击的骑士,即两点之间的边不可选取,两点之间的联系必须断开
//断开联系也就相当于删去 最小点覆盖

bool find(int x, int y) {
	for (int i = 0; i < 8; i++) { //走日八个方向
		int ix = x + dx[i], iy = y + dy[i];
		if (ix <= 0 || iy <= 0 || ix > n || iy > m || g[ix][iy] || st[ix][iy])continue;

		st[ix][iy] = true;
		PII t = match[ix][iy];
		if (t.fx == 0 || find(t.fx, t.fy)) {
			match[ix][iy] = { x,y };
			return true;
		}
	}
	return false;
}

int main() {
	cinios;

	cin >> n >> m >> k;
	for (int i = 0; i < k; i++)
	{
		int a, b;
		cin >> a >> b;
		g[a][b] = true;
	}

	int ans = n * m - k;//点数 == 总点数 减去 不能放骑士的格子
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			if (i + j & 1 && !g[i][j]) {
				mem(st, 0);
				if (find(i, j))ans--;//有一个匹配就相当于有一个点覆盖
				//减去
			}

	cout << ans;//就能得到答案

	return 0;
}

——————————————————————————————————————————

二分图 最大路径点覆盖 与 最大路径重复点覆盖 应用:

最小路径点覆盖含义:
用最少的点,覆盖图中全部的 不相交 路径,这个路径数是多少?
等于总点数 - 最小点覆盖 / 最大匹配数

最小路径点重复覆盖含义:
用最少的点,覆盖图中全部路径(可以有分叉),这个路径数是多少?
等于 对图做一个传递闭包后的 总点数 - 最小点覆盖 / 最大匹配数

Acwing:捉迷藏


代码:

#include<bits/stdc++.h>
#include<unordered_set>
#include<unordered_map>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define sca scanf
#define pri printf
#define ul (u << 1)
#define ur (u << 1 | 1)
#define fx first
#define fy second
//#pragma GCC optimize(2)
//[博客地址](https://blog.csdn.net/weixin_51797626?t=1) 
using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

const int N = 210, M = 10010, MM = 3000010;
int INF = 0x3f3f3f3f, mod = 100003;
ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k, T, S, D;
int match[N];
bool st[N], g[N][N];

//最小路径点覆盖含义:
//用最少的点,覆盖图中全部的 不相交 路径,这个路径数是多少?
//等于总点数 - 最小点覆盖 / 最大匹配数
// 
//最小路径点重复覆盖含义:
//用最少的点,覆盖图中全部路径(可以有分叉),这个路径数是多少?
//等于 对图做一个传递闭包后的 总点数 - 最小点覆盖 / 最大匹配数

//此类问题为单向无环图,建二分图比较特殊
//给出的 n 个点作为起点,再虚构 n 个点作为终点,单向边就是左边连右边

//连在一条边上的两点显然在一条路径上,这 n 个点中的孤立点就是某路径的终点
//此题要求:选出最多多少个点,保证这些点相互之间都不在同一路径上

bool find(int x) {
	for (int i = 1; i <= n; i++)
		if (!st[i] && g[x][i]) {
			st[i] = true;
			if (match[i] == 0 || find(match[i])) {
				match[i] = x;
				return true;
			}
		}
	return false;
}

int main() {
	cinios;

	cin >> n >> m;
	while (m--)
	{
		int a, b;
		cin >> a >> b;
		g[a][b] = true;
	}

	for (int k = 1; k <= n; k++)//传递闭包
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				g[i][j] |= g[i][k] & g[k][j];//让所有点都尽可能匹配到

	int res = 0;
	for (int i = 1; i <= n; i++) {
		mem(st, 0);
		if (find(i))res++;
	}
	cout << n - res;

	return 0;
}

——————————————————————————————————————————

笔记做吐了ou

有关二分图(概念、相关算法和题目应用)(全面整理)的更多相关文章

  1. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  2. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  3. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  4. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  5. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  6. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

  7. ruby-on-rails - 如何在 Gem 中获取 Rails 应用程序的根目录 - 2

    是否可以在应用程序中包含的gem代码中知道应用程序的Rails文件系统根目录?这是gem来源的示例:moduleMyGemdefself.included(base)putsRails.root#returnnilendendActionController::Base.send:include,MyGem谢谢,抱歉我的英语不好 最佳答案 我发现解决类似问题的解决方案是使用railtie初始化程序包含我的模块。所以,在你的/lib/mygem/railtie.rbmoduleMyGemclassRailtie使用此代码,您的模块将在

  8. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  9. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  10. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

随机推荐