[八省联考2018] 劈配 (网络流+二分)
题目大意:略
先考虑第一问
直接跑最大流肯定是不好使的
考虑动态地进行这个过程
枚举每个选手,枚举每一等级的志愿
把选手向当前志愿内的每个导师都连流量为1的边,然后找增广路
如果找不到增广路,说明在当前等级志愿内并不能找到合法导师,删掉当前状态下选手和导师的所有边,继续枚举下一等级志愿
如果找到了增广路,说明存在合法导师,跳出。并继续枚举下一个选手
写个伪代码:
for 选手1~n
for 志愿等级1~m
1.把选手向当前等级志愿内的所有导师连流量为1的边
2.找不到增广路:删掉所有和导师间的连边
找到了增广路:跳出
正确性似乎显然啊
第二个问怎么搞?
发现这个问题具有单调性,考虑二分
验证需要还原加入前mid个选手的图,可持久化网络流?其实在加入每个选手以后都把图存一遍就行了
1 #include <vector> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define L1 205 6 #define N1 410 7 #define M1 3050 8 using namespace std; 9 const int inf=0x3f3f3f3f; 10 11 template <typename _T> void read(_T &ret) 12 { 13 ret=0; _T fh=1; char c=getchar(); 14 while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); } 15 while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); } 16 ret=ret*fh; 17 } 18 19 struct Edge{ 20 int to[M1*2],nxt[M1*2],flow[M1*2],head[M1*2],cte; 21 void ae(int u,int v,int f) 22 { cte++; to[cte]=v; flow[cte]=f; nxt[cte]=head[u]; head[u]=cte; } 23 }E,o[L1]; 24 25 int n,m,S,T,hd,tl; 26 int dep[N1],cur[N1],que[N1]; 27 28 int bfs(Edge &e) 29 { 30 int x,j,v; 31 memset(dep,-1,(T+1)*4); memcpy(cur,e.head,(T+1)*4); 32 hd=1,tl=0; que[++tl]=S; dep[S]=0; 33 while(hd<=tl) 34 { 35 x=que[hd++]; 36 for(j=e.head[x];j;j=e.nxt[j]) 37 { 38 v=e.to[j]; 39 if(dep[v]==-1 && e.flow[j]>0) 40 dep[v]=dep[x]+1, que[++tl]=v; 41 } 42 } 43 return dep[T]!=-1; 44 } 45 int dfs(Edge &e,int x,int limit) 46 { 47 if(x==T||!limit) return limit; 48 int j,v,flow,ans=0; 49 for(j=cur[x];j;j=e.nxt[j]) 50 { 51 v=e.to[j]; cur[x]=j; 52 if(dep[v]==dep[x]+1 && (flow=dfs(e,v,min(e.flow[j],limit)))) 53 { 54 e.flow[j]-=flow; limit-=flow; 55 e.flow[j^1]+=flow; ans+=flow; 56 if(!limit) break; 57 } 58 } 59 return ans; 60 } 61 int Dinic(Edge &e) 62 { 63 int mxflow=0; 64 while(bfs(e)) mxflow+=dfs(e,S,inf); 65 return mxflow; 66 } 67 68 vector<int>ccf[L1]; 69 int b[L1],a[L1][L1],want[L1]; 70 71 int solve(Edge &e,int x) 72 { 73 int i,j,k,now,tmp; 74 e.ae(S,x,1); e.ae(x,S,0); now=e.cte; 75 for(i=0;i<=m;i++) ccf[i].clear(); 76 for(i=1;i<=m;i++) ccf[a[x][i]].push_back(i); 77 for(i=1;i<=m;i++) if(ccf[i].size()>0) 78 { 79 for(k=0;k<ccf[i].size();k++) 80 e.ae(x,ccf[i][k]+n,1), e.ae(ccf[i][k]+n,x,0); 81 tmp=Dinic(e); 82 if(!tmp) 83 { 84 for(k=ccf[i].size()-1;k>=0;k--) 85 e.head[x]=e.nxt[e.head[x]], e.head[ccf[i][k]+n]=e.nxt[e.head[ccf[i][k]+n]]; 86 e.cte=now; continue; 87 } 88 break; 89 } 90 memcpy(&o[x],&e,sizeof(o[x])); 91 return i; 92 } 93 94 int id[N1],real[N1],happy[N1]; 95 96 int check(int limit,int x) 97 { 98 int i,j,ans=0; 99 memcpy(&E,&o[limit-1],sizeof(E)); 100 E.ae(S,x,1); E.ae(x,S,0); 101 for(i=1;i<=m;i++) if(0<a[x][i] && a[x][i]<=want[x]) E.ae(x,i+n,1), E.ae(i+n,x,0); 102 ans=Dinic(E); 103 if(ans>0) return 1; else return 0; 104 } 105 void init(); 106 107 void _Main_() 108 { 109 init(); 110 int i,j,k,tmp,x,mid; E.cte=1; 111 scanf("%d%d",&n,&m); S=0; T=n+m+1; 112 for(i=1;i<=m;i++) read(b[i]), E.ae(i+n,T,b[i]), E.ae(T,i+n,0); 113 for(i=1;i<=n;i++) for(j=1;j<=m;j++) read(a[i][j]); 114 for(i=1;i<=n;i++) read(want[i]); 115 memcpy(&o[0],&E,sizeof(o[0])); 116 for(i=1;i<=n;i++) 117 { 118 real[i]=solve(E,i); 119 } 120 for(i=1;i<=n;i++) printf("%d ",real[i]); puts(""); 121 int l,r; 122 for(i=1;i<=n;i++) 123 { 124 if(real[i]<=want[i]){ happy[i]=0; continue; } 125 l=1; r=i-1; happy[i]=i; 126 while(l<=r) 127 { 128 mid=(l+r)>>1; 129 if(check(mid,i)) happy[i]=i-mid, l=mid+1; 130 else r=mid-1; 131 } 132 } 133 for(i=1;i<=n;i++) printf("%d ",happy[i]); puts(""); 134 } 135 136 int TT,CC; 137 int main() 138 { 139 scanf("%d%d",&TT,&CC); 140 while(TT--) _Main_(); 141 return 0; 142 } 143 144 void init() 145 { 146 memset(id,0,sizeof(id)); memset(real,0,sizeof(real)); memset(happy,0,sizeof(happy)); 147 memset(&E,0,sizeof(E)); memset(o,0,sizeof(o)); 148 }