「题解」洛谷 P6054 [RC-02] 开门大吉

「题解」洛谷 P6054 [RC-02] 开门大吉

一套题里面的各个题是假的,可以处理出 wi,j 为第 i 个人选第 j 套题的期望得分。

对于每个人来讲,有 m 种选择套题,只能选择一个套题,要求价值最小,于是想到一个最小割的经典建图:对于每个人,从 ST 连一条长度为 m 的链,边的流量依次为这个人选择第 i 套题的期望得分。

考虑怎样描述限制,若割了 j 的第 l 条边,那么就不能割 i 的前 (j+k1) 条边。

那么就从 j 的第 l 条边的起点,向 i 的前 (j+k1) 条边的终点连一条 +

但是要注意到,限制和限制之间是有传递性的,假若有 121231,那么还需要满足 132

将一开始 ST 的若干条长度为 m 的链,连一条反向的流量为 + 的边,这样限制和限制组成的限制也被满足了。

最小割 建图模型:每个位置 n1,求最小代价,ST 连若干条长度为 n,流量依次为每种选择的代价,求最小割。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#define pb emplace_back
#define mp std::make_pair
#define fi first
#define se second
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;
typedef std::vector<int> vi;
const ll mod = 998244353;
ll Add(ll x, ll y) { return (x+y>=mod) ? (x+y-mod) : (x+y); }
ll Mul(ll x, ll y) { return x * y % mod; }
ll Mod(ll x) { return x < 0 ? (x + mod) : (x >= mod ? (x-mod) : x); }
ll cadd(ll &x, ll y) { return x = (x+y>=mod) ? (x+y-mod) : (x+y); }
ll cmul(ll &x, ll y) { return x = x * y % mod; }
template <typename T> T Max(T x, T y) { return x > y ? x : y; }
template<typename T, typename... T2> T Max(T x, T2 ...y) { return Max(x, y...); }
template <typename T> T Min(T x, T y) { return x < y ? x : y; }
template<typename T, typename... T2> T Min(T x, T2 ...y) { return Min(x, y...); }
template <typename T> T cmax(T &x, T y) { return x = x > y ? x : y; }
template <typename T> T cmin(T &x, T y) { return x = x < y ? x : y; }
template <typename T>
T &read(T &r) {
	r = 0; bool w = 0; char ch = getchar();
	while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
	while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
	return r = w ? -r : r;
}
template<typename T1, typename... T2>
void read(T1 &x, T2& ...y) { read(x); read(y...); }
const int N = 100010;
const int M = 500010;
const ll INF = 0x7fffffffffffffff;
const ld eps = 1e-10;
int n, m, p, y, c[N], pos[81][81];
ld f[81][81][81], w[81][81];
int tot, S, T, ent = 1, head[N], cur[N], dis[N];
struct Edge {
	int to, nxt;
	ld fl;
}e[M];
inline void add(int x, int y, ld z) {
	e[++ent].to = y; e[ent].fl = z; e[ent].nxt = head[x]; head[x] = ent;
	e[++ent].to = x; e[ent].fl = 0; e[ent].nxt = head[y]; head[y] = ent;
}
bool bfs() {
	for(int i = 1; i <= tot; ++i) dis[i] = -1, cur[i] = head[i];
	std::queue<int>q;
	q.push(S); dis[S] = 0;
	while(!q.empty()) {
		int x = q.front(); q.pop();
		for(int i = head[x]; i; i = e[i].nxt) {
			int v = e[i].to;
			if(dis[v] == -1 && e[i].fl > eps) {
				dis[v] = dis[x] + 1;
				q.push(v);
			}
		}
	}
	return dis[T] != -1;
}
bool qwqbfs() {
	for(int i = 1; i <= tot; ++i) dis[i] = -1;
	std::queue<int>q;
	q.push(S); dis[S] = 0;
	while(!q.empty()) {
		int x = q.front(); q.pop();
		for(int i = head[x]; i; i = e[i].nxt) {
			int v = e[i].to;
			if(dis[v] == -1 && e[i].fl == INF) {
				dis[v] = dis[x] + 1;
				q.push(v);
			}
		}
	}
	return dis[T] != -1;
}
ld dfs(int x, ld lim) {
	if(x == T) return lim;
	ld flow = 0;
	for(int i = cur[x]; i && flow < lim; i = e[i].nxt) {
		int v = e[i].to; cur[x] = i;
		if(dis[v] == dis[x] + 1 && e[i].fl > eps) {
			ld f = dfs(v, Min(e[i].fl, lim - flow));
			flow += f; e[i].fl -= f; e[i^1].fl += f;
		}
	}
	return flow;
}
ld dinic() {
	ld mxfl = 0;
	while(bfs())
		mxfl += dfs(S, INF);
	return mxfl;
}
void solve() { for(int i = 1; i <= tot; ++i) head[i] = 0; tot = 0; ent = 1;
	read(n, m, p, y);
	for(int i = 1; i <= p; ++i) read(c[i]);
	for(int j = 1; j <= m; ++j)
		for(int i = 1; i <= n; ++i)
			for(int k = 1; k <= p; ++k) {
				double qwq; scanf("%lf", &qwq);
				f[i][j][k] = qwq;
			}
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j) {
			ld t = 1; w[i][j] = 0;
			for(int k = 1; k <= p; ++k) {
				t *= f[i][j][k];
				w[i][j] += t * c[k];
			}
		}
	S = ++tot; T = ++tot;
	for(int i = 1; i <= n; ++i) {
		pos[i][0] = S;
		for(int j = 1; j <= m; ++j) {
			if(j < m) pos[i][j] = ++tot;
			else pos[i][j] = T;
			add(pos[i][j-1], pos[i][j], w[i][j]);
			add(pos[i][j], pos[i][j-1], INF);
		}
	}
	for(int o = 1; o <= y; ++o) {
		int i, j, k; read(i, j, k);
		for(int a = 1; a <= m; ++a)
			if(a-1+k >= 1 && a-1+k <= m)
				add(pos[j][a-1], pos[i][a-1+k], INF);
	}
	if(qwqbfs()) {
		puts("-1");
		return ;
	}
	double qwq = dinic();
	printf("%lf\n", qwq);
}
signed main() {
	int T; read(T);
	while(T--)
		solve();
	return 0;
}
posted @   do_while_true  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?

This blog has running: 1845 days 1 hours 33 minutes 22 seconds

点击右上角即可分享
微信分享提示