2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)- 占座位(最小割)
生活随笔
收集整理的這篇文章主要介紹了
2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)- 占座位(最小割)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目大意:給出一個 n?mn*mn?m 的矩陣,每個格子都有兩個權值 aaa 和 bbb,分別代表花費和收益。一個格子被占,當且僅當:
格子被占可以獲得收益 bbb,格子上有人需要花費 aaa,問如何分配可以使得收益最高。
題目分析:很經典,但我不會的一個模型。
拆點最小割,首先棋盤問題不難想到奇偶拆點,在此基礎上將每個點再拆一下用來維護 bbb,再加點無窮大的邊用來調和 aaa:
上圖中 x1x_1x1? 和 x2x_2x2? 是奇數點的入點和出點, y1y_1y1? 和 y2y_2y2? 是偶數點的入點和出點。
那么此時最小割就只有三種情況:
不難看出,上述三種情況實質上對應著本題的兩個條件,也就是對于某個點,獲得 bbb 時的兩種情況:
所以最后用 ∑b\sum b∑b 減去最小割就是最大的答案了。
代碼:
// #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=4100; template<typename T> struct Dinic {const static int N=4100;const static int M=N*N;const T inf=0x3f3f3f3f3f3f3f3f;struct Edge{int to,next;T w;}edge[M];//邊數int head[N],cnt;void addedge(int u,int v,T 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;T 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;}T dinic(int x,int t,T flow)//更新答案{if(x==t)return flow;T rest=flow,i;for(i=now[x];i!=-1&&rest;i=edge[i].next){int v=edge[i].to;T w=edge[i].w;if(w&&d[v]==d[x]+1){T 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(){memset(now,0,sizeof(now));memset(head,-1,sizeof(head));cnt=0;}T solve(int st,int ed){T ans=0,flow;while(bfs(st,ed))while(flow=dinic(st,ed,inf))ans+=flow;return ans;} }; Dinic<int>t; const int b[4][2]={0,1,0,-1,1,0,-1,0}; int id[50][50][2],tot; int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);t.init();int n,m,st=N-1,ed=st-1,sum=0;read(n),read(m);for(int i=1;i<=n;i++) {for(int j=1;j<=m;j++) {for(int k=0;k<2;k++) {id[i][j][k]=++tot;}}}for(int i=1;i<=n;i++) {for(int j=1;j<=m;j++) {int a;read(a);if((i+j)&1) t.addedge(st,id[i][j][0],a);else t.addedge(id[i][j][1],ed,a);}}for(int i=1;i<=n;i++) {for(int j=1;j<=m;j++) {int b;read(b);t.addedge(id[i][j][0],id[i][j][1],b);sum+=b;}}for(int x=1;x<=n;x++) {for(int y=1;y<=m;y++) {if((x+y)&1) {for(int k=0;k<4;k++) {int xx=x+b[k][0],yy=y+b[k][1];if(xx<=0||xx>n||yy<=0||yy>m) continue;for(int i=0;i<2;i++) t.addedge(id[x][y][i],id[xx][yy][i],inf);}}}}cout<<sum-t.solve(st,ed)<<endl;return 0; }總結
以上是生活随笔為你收集整理的2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)- 占座位(最小割)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021-2022年度第三届全国大学生算
- 下一篇: 2021年中国大学生程序设计竞赛 女生专