题目大意: n个人m个题目,每个题要r分钟完成。比赛有t分钟。给出每个人会做哪些题目,请你安排一个每个人在什么时候做什么题目,使得做出来的题目数最多。在做题数一样多的情况下,罚时尽量小。
应该很容易看出来是一个流的模型。每个人一共能做的题目数量是固定的。所以最大流即可。但是怎么让罚时最少呢?肯定是大家一起做题,而不是一个人做多道题。所以我们可以动态加边,每次都只加流量为1的边,直到最大流不增加为止,或者比赛结束为止。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int inf=0x3f3f3f3f;
const int N=1e3+10,M=1e6+10;
int n,m,s,t,a1,a2,k,h[N],res,tot_time,cnt[N];
int head[N],nex[M],to[M],w[M],tot=1;
struct node{int a,b,c;}; vector<node> v;
inline void ade(int a,int b,int c){
to[++tot]=b; nex[tot]=head[a]; w[tot]=c; head[a]=tot;
}
inline void add(int a,int b,int c){ade(a,b,c); ade(b,a,0);}
inline int bfs(){
queue<int> q; q.push(s); memset(h,0,sizeof h); h[s]=1;
while(q.size()){
int u=q.front(); q.pop();
for(int i=head[u];i;i=nex[i]){
if(!h[to[i]]&&w[i]){
h[to[i]]=h[u]+1; q.push(to[i]);
}
}
}
return h[t];
}
int dfs(int x,int f){
if(x==t) return f; int fl=0;
for(int i=head[x];i&&f;i=nex[i]){
if(w[i]&&h[to[i]]==h[x]+1){
int mi=dfs(to[i],min(w[i],f));
w[i]-=mi,w[i^1]+=mi,fl+=mi,f-=mi;
}
}
if(!fl) h[x]=-1;
return fl;
}
inline int dinic(){
int res=0;
while(bfs()) res+=dfs(s,inf);
return res;
}
signed main(){
cin>>n>>m>>a1>>a2>>k; t=n+m+2;
for(int i=1,a,b;i<=k;i++) cin>>a>>b,add(a,b+n,1);
for(int i=1;i<=m;i++) add(i+n,t,1);
for(int i=1;i<=(a2/a1);i++){
for(int j=1;j<=n;j++) add(s,j,1);
int t=dinic();
if(!t) break; res+=t;
}
for(int i=1;i<=n;i++){
for(int j=head[i];j;j=nex[j]){
if(to[j]==s||w[j]) continue;
v.push_back({i,to[j]-n,cnt[i]}); cnt[i]+=a1;
tot_time+=cnt[i];
}
}
cout<<res<<' '<<tot_time<<'\n';
for(int i=0;i<v.size();i++) cout<<v[i].a<<' '<<v[i].b<<' '<<v[i].c<<'\n';
return 0;
}