1 条题解
-
0
自动搬运
来自洛谷,原作者为

C_S_X_
**搬运于
2025-08-24 21:49:53,当前版本为作者最后更新于2018-12-19 14:05:14,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
最大流
(罚时:每道题被完成的 时间点 之和)
先不看罚时最小的要求,只考虑做题数量最多,可以像这样建图:
1 每个人连向自己会做的题,由于一个人只会做一道题一次,所以容量为1
2 每道题连向汇点,由于一道题只需要被做一次,所以容量为1
3 源点连向每个人,由于每个人最多的做题数为t/r,所以容量填t/r
最大流就是最大做题数
再考虑罚时最小,就是要求从比赛开始,要尽可能更多人在做题,上面这种建图的缺陷在于可能一个人包揽了很多题,导致罚时很大(
明明他可以让别人做一些)导致这种为题就在于源点向人连的边容量过大,一开始允许他做很多题。所以可以动态加边,每次加一组源点到人的容量为1的边,慢慢开放他们做题的权限,防止一个人疯狂做题,直到某一次即使加边他们也做不出更多的题目,目前的流量图就是一个合法的方案。
输出方案:对于每条人到题目正向边,如果被流满则这个人做了这道题。
#include<bits/stdc++.h> #define N 500000 #define inf 1000000007 using namespace std; int n,m,r,t,k,first[N],nxt[N],tot=1,S,T; int in1[N],in2[N],depth[N],maxflow=0,flow,max_num,last=0,ans=0; int ans1[N],ans2[N],ans3[N],tpp=0,p[N]={0}; queue <int> q; struct Edge { int u,v,flow; }edge[N]; void Add(int u,int v,int flow) { tot++; nxt[tot]=first[u]; first[u]=tot; edge[tot]=(Edge){u,v,flow}; return; } void Addedge(int u,int v,int flow) { Add(u,v,flow); Add(v,u,0); return; } int bfs() { memset(depth,0,sizeof(depth)); while (q.size()) q.pop(); depth[S]=1; q.push(S); while (q.size()) { int tmp=q.front(); q.pop(); for (int j=first[tmp];j!=-1;j=nxt[j]) if (edge[j].flow&&!depth[edge[j].v]) { int to=edge[j].v; depth[to]=depth[tmp]+1; q.push(to); } } if (depth[T]) return 1; else return 0; } int Dinic(int p,int f) { if (p==T) return f; int k,rest=f; for (int j=first[p];j!=-1&&rest;j=nxt[j]) if (edge[j].flow&&depth[edge[j].v]==depth[p]+1) { int to=edge[j].v; k=Dinic(to,min(rest,edge[j].flow)); if (!k) { depth[to]=0; continue; } edge[j].flow-=k; edge[j^1].flow+=k; rest-=k; } return f-rest; } int main() { // freopen("1.in","r",stdin); // freopen("1.out","w",stdout); memset(first,-1,sizeof(first)); scanf("%d%d%d%d%d",&n,&m,&r,&t,&k); S=n+m+1; T=n+m+2; for (int i=1;i<=k;i++) scanf("%d%d",&in1[i],&in2[i]); for (int i=1;i<=k;i++) Addedge(in1[i],in2[i]+n,1); for (int i=n+1;i<=n+m;i++) Addedge(i,T,1); max_num=t/r; for (int i=1;i<=max_num;i++) { for (int i=1;i<=n;i++) Addedge(S,i,1); while (bfs()) while ((flow=Dinic(S,inf))) maxflow+=flow; if (maxflow==last) break; last=maxflow; } for (int i=2;i<=tot;i+=2) { int p1=edge[i].u,p2=edge[i].v; if (edge[i].flow==0&&p1!=S&&p2!=T&&i%2==0) { tpp++; ans1[tpp]=p1; ans2[tpp]=p2-n; ans3[tpp]=p[p1]*r; p[p1]++; ans+=ans3[tpp]+r; } } printf("%d %d\n",maxflow,ans); for (int i=1;i<=tpp;i++) printf("%d %d %d\n",ans1[i],ans2[i],ans3[i]); // for (int i=2;i<=tot;i+=2) printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].flow); return 0; }
- 1
信息
- ID
- 2605
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者