题目大意:
思路:
一道很普通的mcmf,取一个学生的a值或者b值可以用流量来表示,即每个学生有1的流量。题目中我要求输出对与每个学生的被选择情况,我们可以通过遍历学生的正向边或者反向边的流量得出学生的被选择情况。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL N = 3010;
struct node
{
LL v, flow, cost, next;
}edge[N*N];
LL head[N], dis[N], vis[N], pre[N], rec[N], cnt;
queue<LL> q;
inline void init()
{
cnt = 0;
memset(head, -1, sizeof(head));
}
inline void add_edge(LL u, LL v, LL f, LL c)
{
edge[cnt].v = v; edge[cnt].flow = f; edge[cnt].cost = c;
edge[cnt].next = head[u]; head[u] = cnt++;
edge[cnt].v = u; edge[cnt].flow = 0; edge[cnt].cost = -c;
edge[cnt].next = head[v]; head[v] = cnt++;
}
LL SPFA(LL s, LL t)
{
memset(dis, 0x3f, sizeof dis);
memset(vis, 0, sizeof vis);
while(!q.empty()) q.pop();
q.push(s); dis[s] = 0; vis[s] = 1;
while(!q.empty())
{
LL tp = q.front(); q.pop();
vis[tp] = 0;
LL k = head[tp];
while(k != -1)
{
if(dis[edge[k].v] > dis[tp] + edge[k].cost && edge[k].flow)
{
dis[edge[k].v] = dis[tp] + edge[k].cost;
pre[edge[k].v] = tp; rec[edge[k].v] = k;
if(vis[edge[k].v] == 0)
{
vis[edge[k].v] = 1;
q.push(edge[k].v);
}
}
k = edge[k].next;
}
}
if(dis[t] == INF) return 0;
return 1;
}
pair<LL, LL> Mcmf(LL s, LL t)
{
LL minflow, k, mincost = 0, maxflow = 0;
while(SPFA(s, t))
{
k = t; minflow = INF;
while(k != s)
{
minflow = min(minflow, edge[rec[k]].flow);
k = pre[k];
}
k = t; maxflow += minflow;
while(k != s)
{
mincost += minflow*edge[rec[k]].cost;
edge[rec[k]].flow -= minflow;
edge[rec[k]^1].flow += minflow;
k = pre[k];
}
}
return make_pair(maxflow, mincost);
}
LL a[N], b[N];
vector<LL> qa;
vector<LL> qb;
int main()
{
init(); // do not forget it
LL n, m, s, t, pp, ps, valp, vals;
cin >> n >> valp >> vals;
s = 0;
pp = n + 1;
ps = n + 2;
t = n + 3;
for (LL i = 1; i <= n; i++) cin >> a[i];
for (LL i = 1; i <= n; i++) cin >> b[i];
for (LL i = 1; i <= n; i++) {
add_edge(s, i, 1, 0);
add_edge(i, pp, 1, -a[i]);
add_edge(i, ps, 1, -b[i]);
}
add_edge(pp, t, valp, 0);
add_edge(ps, t, vals, 0);
pair<LL, LL> ans = Mcmf(s, t);
cout << -1LL * ans.second << endl;
for (LL i = 1; i <= n; i++) {
for (LL j = head[i]; ~j; j = edge[j].next) {
// if (edge[j].flow) continue; //not be used
if(!edge[j ^ 1].flow) continue; //反向边没有流量,说明正向边没有被使用
if (edge[j].v == pp) qa.push_back(i);
if (edge[j].v == ps) qb.push_back(i);
}
}
for (auto i : qa) cout << i << " ";
cout << endl;
for (auto i : qb) cout << i << " ";
cout << endl;
return 0;
}