目录
显示
题目链接
https://www.luogu.com.cn/problem/P4382
题解
Problem 1
根据题意,前 \(i\) 人最优的前提是前 \(i-1\) 人最优。
因此我们只需按名次顺序处理每一个人,处理到 \(u\) 的时候将 \(u\) 的志愿按顺序加入二分图中。每加入一个志愿就增广一次,如果存在增广路则这个人被该志愿录取。
这里存在一个优化:如果 \(u\) 不能被 \(x\) 志愿录取,可以把这个志愿对应的边全部移除(这些边的存在显然是无用的)。
为了方便起见,我们可以把前 \(i\) 个人对应的最优情况图全部存下来,这将方便我们解决第二问。
Problem 2
第二问我们可以二分答案。
设我们把 \(u\) 提升到第 \(p\) 名,则我们可以直接利用前 \(p-1\) 名的最优解,在这个基础上加入 \(u\) 的前 \(s_i\) 个志愿。如果存在增广路则说明是可以的。
#include <cstring> #include <iostream> #include <vector> #include <queue> #include <algorithm> #define INF 0x3f3f3f3f using namespace std; struct graph { struct edge { int v,w,rev; }; vector<edge> e[505]; int cnt=1,s,t; int vis[505],cur[505],dis[505]; void addedge(int u,int v,int w) { e[u].push_back({v,w,(int)e[v].size()}); e[v].push_back({u,0,(int)e[u].size()-1}); } void deledge(int u,int v) { e[u].pop_back(); e[v].pop_back(); } void init(int S,int T) { cnt=1; for(int i=1;i<=T;i++) e[i].clear(); s=S,t=T; } bool bfs() { queue<int> q; memset(dis,INF,sizeof(dis)); memset(cur,0,sizeof(cur)); dis[s]=0,vis[s]=1; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(auto ed:e[u]) if(ed.w&&dis[ed.v]>dis[u]+1) { dis[ed.v]=dis[u]+1; if(!vis[ed.v])q.push(ed.v); } } return dis[t]!=INF; } int dfs(int u,int flow) { if(u==t)return flow; int siz=e[u].size(),used=0; for(int i=cur[u];i<siz;i++) { cur[u]=i; int v=e[u][i].v; if(dis[v]==dis[u]+1&&e[u][i].w) { int w=dfs(v,min(e[u][i].w,flow-used)),rev=e[u][i].rev; e[u][i].w-=w; e[v][rev].w+=w; used+=w; if(used==flow)break; } } return used; } }g[205]; int n,m,s,t,b[205],p[205]; vector<int> a[205][205]; namespace pro1 { int res[205]; void init() { for(int i=1;i<=n;i++) res[i]=m+1; for(int i=1;i<=m;i++) g[0].addedge(i+n,t,b[i]); } void solve() { init(); int ans=0; for(int i=1;i<=n;i++) { g[i]=g[i-1]; g[i].addedge(s,i,1); for(int j=1;j<=m;j++) { bool flag=false; for(auto v:a[i][j]) g[i].addedge(i,v+n,1); while(g[i].bfs()) ans+=g[i].dfs(s,INF),flag=true; if(!flag) for(auto v:a[i][j]) g[i].deledge(i,v+n); else { res[i]=j; break; } } } for(int i=1;i<=n;i++) cout<<res[i]<<' '; cout<<endl; } } namespace pro2 { int res[205],vis[205]; bool check(int x,int u) { auto G=g[x-1]; G.addedge(s,u,1); for(int i=1;i<=p[u];i++) for(auto v:a[u][i]) G.addedge(u,v+n,1); return G.bfs(); } void solve() { memset(res,0,sizeof(res)); memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) { if(pro1::res[i]<=p[i]) { res[i]=0; continue; } int l=1,r=i-1; while(l<=r) { int mid=(l+r)>>1; if(check(mid,i))vis[i]=mid,l=mid+1; else r=mid-1; } res[i]=(vis[i]?i-vis[i]:i); } for(int i=1;i<=n;i++) cout<<res[i]<<' '; cout<<endl; } } int main() { ios::sync_with_stdio(false); int T,c; cin>>T>>c; while(T--) { for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j].clear(); cin>>n>>m; s=n+m+1,t=n+m+2; g[0].init(n+m+1,n+m+2); for(int i=1;i<=m;i++) cin>>b[i]; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { int x; cin>>x; if(x)a[i][x].push_back(j); } for(int i=1;i<=n;i++) cin>>p[i]; pro1::solve(); pro2::solve(); } return 0; }