2021牛客多校3 - Minimum grid(二分图最大匹配-最大流)
題目鏈接:點擊查看
題目大意:給出一個 n?nn*nn?n 的棋盤,其中有 mmm 個位置是需要填數字的位置,每個位置需要填 [0,k][0,k][0,k] 的數字中的其中一個,可以重復,現在給出每一行的最大值和每一列的最大值,要求填出一種合法的方案,且權值和最小,題目保證一定有解
題目分析:
首先考慮行最大值和列最大值的最大值,記為 xxx,找到最大值需要等于 xxx 的行和列,設有 nnn 行和 mmm 列的最大值需要等于 xxx。原本是需要在每一行、每一列共 n+mn+mn+m 個位置放置 xxx,發現如果在他們交叉位置放置 xxx 的話,可以少放置一些 xxx,每有一對行和列匹配,就可以少放置一個 xxx,如此一來轉換成了二分圖最大匹配問題
考慮完了 xxx 后,再考慮次大值 yyy,我們發現如果將 yyy 放在原本應該放置 xxx 的行或列的話,并不會對答案造成影響,又因為題目保證了一定有解,加上我們也并不關心到底該如何去放置,所以對于 yyy 來說,在可以匹配的交叉點放置 yyy,其余沒有匹配到的位置一定是存在著可以放置的位置的
所以綜上所述,對于權值 www 來說,提供的貢獻就是 (n+m?match)?w(n+m-match)*w(n+m?match)?w,其中 matchmatchmatch 是最大匹配數
到此觀察到題目中有一句特別顯眼的“提示”:(b[i]b[i]b[i] 和 c[i]c[i]c[i] 分別是行最大值和列最大值)
所以每次建圖最多有 500500500 個點, 5002=2e5500^2=2e55002=2e5 條邊,跑二分圖最大匹配的話,用匈牙利或最大流都是可以的
代碼:
// Problem: Minimum grid // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/11254/C // Memory Limit: 524288 MB // Time Limit: 6000 ms // // Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<list> #include<unordered_map> #define lowbit(x) (x&-x) using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=8e6+100; vector<int>node[1000100]; bool maze[2010][2010]; struct Edge {int to,w,next; }edge[N];//邊數 int head[N],cnt; void addedge(int u,int v,int w) {edge[cnt].to=v;edge[cnt].w=w;edge[cnt].next=head[u];head[u]=cnt++;edge[cnt].to=u;edge[cnt].w=0;//反向邊邊權設置為0edge[cnt].next=head[v];head[v]=cnt++; } int d[N],now[N];//深度 當前弧優化 bool bfs(int s,int t)//尋找增廣路 {memset(d,0,sizeof(d));queue<int>q;q.push(s);now[s]=head[s];d[s]=1;while(!q.empty()){int u=q.front();q.pop();for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;int w=edge[i].w;if(d[v])continue;if(!w)continue;d[v]=d[u]+1;now[v]=head[v];q.push(v);if(v==t)return true;}}return false; } int dinic(int x,int t,int flow)//更新答案 {if(x==t)return flow;int rest=flow,i;for(i=now[x];i!=-1&&rest;i=edge[i].next){int v=edge[i].to;int w=edge[i].w;if(w&&d[v]==d[x]+1){int k=dinic(v,t,min(rest,w));if(!k)d[v]=0;edge[i].w-=k;edge[i^1].w+=k;rest-=k;}}now[x]=i;return flow-rest; } void init(int n) {memset(now,0,sizeof(int)*(n+5));memset(head,-1,sizeof(int)*(n+5));cnt=0; } int solve(int st,int ed) {int ans=0,flow;while(bfs(st,ed))while(flow=dinic(st,ed,inf))ans+=flow;return ans; } int solve(vector<int>row,vector<int>col) {if(row.empty()||col.empty()) {return 0;}int lena=row.size(),lenb=col.size();init(lena+lenb+2);int st=lena+lenb,ed=st+1;for(int i=0;i<lena;i++) {addedge(st,i,1);}for(int i=0;i<lenb;i++) {addedge(i+lena,ed,1);}for(int i=0;i<lena;i++) {for(int j=0;j<lenb;j++) {if(maze[row[i]][col[j]]) {addedge(i,j+lena,1);}}}return solve(st,ed); } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int n,m,k;read(n),read(m),read(k);for(int i=1,x;i<=n;i++) {read(x);node[x].push_back(i);}for(int i=1,x;i<=n;i++) {read(x);node[x].push_back(n+i);}while(m--) {int x,y;read(x),read(y);maze[x][y]=true;}LL ans=0;for(int i=k;i>=0;i--) {vector<int>row,col;for(auto it:node[i]) {if(it<=n) {row.push_back(it);} else {col.push_back(it-n);}}ans+=1LL*(row.size()+col.size()-solve(row,col))*i;}cout<<ans<<endl;return 0; }總結
以上是生活随笔為你收集整理的2021牛客多校3 - Minimum grid(二分图最大匹配-最大流)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021牛客多校3 - 24dian(d
- 下一篇: HDU多校1 - 6955 Xor su