题意
有一个 n * m 的白色棋盘,每个格子(i,j)都有一个权重c(i,j),网格被染成黑色的代价是权重。
当任意两行两列
的四个相交方格,其中三个是黑色,那么第四个可以不计成本的染成黑色;
求染黑棋盘的最低成本;
由于格子数量很多,用以下方法来产生权重。
A0 = a;
A(i + 1) = (Ai * Ai * b + Ai * c + d) % p;
其中A(m * (i - 1) + j) 是第 i 行和第 j 列的网格的成本c(i,j);
思路
思路很巧妙,把每一行每一列看成一个点,任意两行两列相交,其中三个点被染成黑色,就是说这两行两列所代表的点已经连通
了,i 到 j 权值是c(i,j),这样问题就转化为,把所有点遍历到,且权值最小,即最小生成树;
在这个题中用 kruskal 算法需要注意不可以排序,排序会超时;
AC代码
Kruskal 算法
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <string>
#include <algorithm>
#include <queue>
#include <utility>
#include <stack>
#include <map>
#include <vector>
#include <set>
#include <iomanip>
#include <unordered_map>
#include <deque>
#define hz020 return
#define mes memset
#define mec memcpy
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll,ll> PII;
const double pi = acos(-1);
const int N = 5010;
const int null = 0x3f3f3f3f,INF = 1e9;
const ll mod = 998244353;
int n, m, a, b, c, d, p;
int fa[10005];
int o;
vector<pii> v[100010];
int find(int x)
{
if (x != fa[x]) fa[x] = find(fa[x]);
return fa[x];
}
ll kruskal()
{
for (int i = 1; i <= n + m; i ++ ) fa[i] = i;
ll res = 0;
for (int i = 0; i < p; i ++ )
{
for (int j = 0; j < v[i].size(); j ++ )
{
int a = v[i][j].x, b = v[i][j].y;
int x = find(a), y = find(b);
if (x != y)
{
fa[x] = y;
res += i;
}
}
}
return res;
}
int main()
{
cin >> n >> m >> a >> b >> c >> d >> p;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
{
a = ((ll)a * a * b + (ll)a * c + d) % p;
v[a].push_back({i, j + n});
}
cout << kruskal() << endl;
hz020 0;
}
Prim 算法
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <string>
#include <algorithm>
#include <queue>
#include <utility>
#include <stack>
#include <map>
#include <vector>
#include <set>
#include <iomanip>
#include <unordered_map>
#include <deque>
#define hz020 return
#define mes memset
#define mec memcpy
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll,ll> PII;
const double pi = acos(-1);
const int N = 10010;
const int null = 0x3f3f3f3f,INF = 1e9;
const ll mod = 998244353;
int n, m, a, b, c, d, p;
int w[N][N];
int dist[N];
bool st[N];
ll prim()
{
mes(dist, 0x3f, sizeof dist);
dist[1] = 0;
ll res = 0;
for (int i = 0; i < n + m; i ++ )
{
int t = -1;
for (int j = 1; j <= n + m; j ++ )
if (!st[j] && (t == -1 || dist[j] < dist[t])) t = j;
st[t] = true;
for (int j = 1; j <= n + m; j ++ )
if (!st[j]) dist[j] = min(dist[j], w[t][j]);
}
for (int i = 1; i <= n + m; i ++ ) res += dist[i];
return res;
}
int main()
{
cin >> n >> m >> a >> b >> c >> d >> p;
mes(w, 0x3f, sizeof w);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
{
a = ((ll)a * a * b + (ll)a * c + d) % p;
w[i][j + n] = a;
w[j + n][i] = a;
}
cout << prim() << endl;
hz020 0;
}