BZOJ5251:[九省联考2018]劈配——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=5251
https://loj.ac/problem/2477? <-可以看數據
https://www.luogu.org/problemnew/show/P4382
題面太長,請自行讀完之后再看本題。
?
考試的時候讓我傷心的一道題,分明想的就是正解結果sb般第二問沒二分丟了15分。
如果b=1就是一個顯然的匈牙利匹配了。
考慮b!=1也只不過就是讓一個導師可以多匹配幾個人而已,額外記錄這個導師是否還能匹配人即可。
那么對于第一問顯而易見匈牙利算法即可完成,復雜度最差就是每個人的其中一個志愿被我們遍歷一遍,于是一次匈牙利是O(n*c),總共O(n^2*c)。
第二問二分答案后對這個點再匈牙利一次,實際就是清出答案和現在這個點之間的點的所有答案,而且我們已經知道了它之前的所有人的志愿和導師選擇,因此大可以直接復制下來而不用重新跑一遍。
因此是O(n^2*logn*c)輕松跑過。
(至于為什么debug這么久純粹是因為我傻,沒有考慮匈牙利算法可以增廣的不只有它前面的點,還可以有后面的點。)
總結:一道好題,洛谷評分虛高,實際為省選/NOI-,但是為了紀念我debug的時間之長,于是評了個NOI。
#include<cmath> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> #include<iostream> using namespace std; const int N=210; inline int read(){int X=0,w=1;char ch=0;while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9')X=(X<<1)+(X<<3)+ch-'0',ch=getchar();return X*w; } int n,m,b[N],bb[N],s[N]; int ds[N],zy[N],dds[N],zzy[N]; int a[N][N][11],len[N][N]; bool vis[N]; bool dfs(int k,int w){for(int j=1;j<=len[k][w];j++){int u=a[k][w][j];if(vis[u])continue;vis[u]=1;if(b[u]){ds[k]=u;zy[k]=w;b[u]--;return 1;}else{for(int l=1;l<=n;l++){//這里debug 3h+才發現。 if(l==k)continue;if(ds[l]==u){if(dfs(l,zy[l])){ds[k]=u;zy[k]=w;return 1;}}}}}return 0; } inline void copy(int k){for(int i=1;i<=m;i++)b[i]=bb[i];for(int i=1;i<=k;i++){ds[i]=dds[i];zy[i]=zzy[i];b[ds[i]]--;}for(int i=k+1;i<=n;i++)ds[i]=-1;return; } inline void work2(){for(int i=1;i<=n;i++){if(zzy[i]<=s[i])printf("0 ");else{int l=1,r=i-1,ans=0;while(l<=r){int mid=(l+r)>>1;bool ok=0;copy(mid-1);memset(vis,0,sizeof(vis));for(int j=1;j<=s[i];j++){if(dfs(i,j)){ans=mid;l=mid+1;ok=1;break;}}if(!ok)r=mid-1;}printf("%d ",i-ans);}}puts(""); } inline void work1(){for(int i=1;i<=n;i++){memset(vis,0,sizeof(vis));for(int j=1;j<=m;j++){if(!len[i][j])continue;if(dfs(i,j))break;}}for(int i=1;i<=n;i++){zzy[i]=zy[i];dds[i]=ds[i];printf("%d ",zy[i]);}puts(""); } inline void init(){n=read(),m=read();memset(len,0,sizeof(len));for(int i=1;i<=m;i++)bb[i]=b[i]=read();for(int i=1;i<=n;i++){zy[i]=m+1;ds[i]=-1;for(int j=1;j<=m;j++){int k=read();if(k)a[i][k][++len[i][k]]=j;}}for(int i=1;i<=n;i++)s[i]=read(); } int main(){int t=read(),c=read();while(t--){init();work1();work2();}return 0; }+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/ +
+++++++++++++++++++++++++++++++++++++++++++
轉載于:https://www.cnblogs.com/luyouqi233/p/8764623.html
總結
以上是生活随笔為你收集整理的BZOJ5251:[九省联考2018]劈配——题解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 共同探索企业级数据库架构之道路
- 下一篇: 【转】Android AlertDial