UVALive6571 It Can Be Arranged(最小路径覆盖)
题意:现在有n个课程,每个课程有一定的参与人数,然后每个课程有开始时间和结束时间ai,bi.
而且给定了一个矩阵clean(ij),表示的是上完i课程需要clean[i][j]的时间打扫卫生才能继续上j课程。也就是说如果上完i课程要上j课程就需要满足条件
b[i]+clean[i][j]<a[j]. 然后每间课室能容纳一定的人数(如果课室30个人,课程有61个人的话,就需要三间教室),问最少要用多少间课室安排全部的课程。
看完题后觉得是网络流,然后想了一下跟大白上讲得一道题很像,就是一个最小路径覆盖,不过这题是带权的。不停地回忆建图方法,但就是想不起来,后来找了师弟借了大白看了一下才想起建模的方法。
对于每个课程i我们建两个点i和i'.如果上完i课程来得及上j课程的话,就i->j'. 然后源点向所以的i点连一条边,容量就是对应的需要开的课室数,然后所有i'点向汇点连边,对应的容量也是需要开的课室数。
最后跑一次最大流,答案就是总的课室数-最大流。原因就是每一条流出去的边看成是重用了已有的课室,每一条流出去的边就相当于节省了多少间课室。过了题说明我的Dicnic模板还是可以用的,不过还是找时间补个SAP- -0
#include <iostream> #include <cstring> #include <string> #include <cstdio> #include <vector> #include <cmath> #include <queue> #include <algorithm> #include <map> #include <vector> #include <string> using namespace std; #define maxn 300 #define maxe 200000 #define inf 0x3f3f3f3f struct Edge { int u,v,cap; int nxt; }edge[maxe]; int head[maxn]; int n,m; int a[maxn],b[maxn],s[maxn]; int mat[maxn][maxn]; struct Dicnic { int level[maxn]; int iter[maxn]; int add; void init() { add=0;memset(head,-1,sizeof(head)); memset(iter,-1,sizeof(iter)); } void insert(int u,int v,int c) { edge[add].u=u;edge[add].v=v; edge[add].cap=c; edge[add].nxt=head[u];head[u]=add++; edge[add].u=v;edge[add].v=u; edge[add].cap=0; edge[add].nxt=head[v];head[v]=add++; } void bfs(int s){ memset(level,-1,sizeof(level)); queue<int> que; level[s]=0; que.push(s); while(!que.empty()){ int v=que.front();que.pop(); for(int i=head[v];i!=-1;i=edge[i].nxt){ Edge &e=edge[i]; if(e.cap>0&&level[e.v]<0){ level[e.v]=level[v]+1; que.push(e.v); } } } } int dfs(int v,int t,int f){ if(v==t) return f; for(int &i=iter[v];i!=-1;i=edge[i].nxt){ Edge &e=edge[i];Edge &reve=edge[i^1]; if(e.cap>0&&level[v]<level[e.v]){ int d=dfs(e.v,t,min(f,e.cap)); if(d>0){ e.cap-=d;reve.cap+=d; return d; } } } return 0; } int max_flow(int s,int t){ int flow=0; for(;;){ bfs(s); if(level[t]<0) return flow; memcpy(iter,head,sizeof(iter)); int f; while((f=dfs(s,t,inf))>0){ flow+=f; } } } }net; int main() { int T;cin>>T;int ca=0; while(T--) { int tot=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d%d%d",a+i,b+i,s+i); } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ scanf("%d",&mat[i][j]); } } net.init(); int ss=0,t=2*n+1; for(int i=1;i<=n;i++){ int num=s[i]/m; if(s[i]%m!=0) num++; net.insert(ss,i,num); tot+=num; net.insert(i+n,t,num); } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(i==j) continue; if(b[i]+mat[i][j]<a[j]){ net.insert(i,n+j,inf); } } } printf("Case %d: %d\n",++ca,tot-net.max_flow(ss,t)); } return 0; }