1. 程式人生 > >YYH的球盒遊戲(NOIP模擬賽Round 6)

YYH的球盒遊戲(NOIP模擬賽Round 6)

ans 當前 read || fff clu pan reg lan

原題傳送門

這題的算法優化真是博大精深、

具體我們一個一個來講。

我們先看這道題的算法,(這。。裸的費用流啊。。。)

然後我們發現負邊(好吧,其實沒有什麽用。spfa可以跑)

首先所有的球都要向源點連費用0,流量為球的數量的邊

然後我們考慮每一個球都要到匯點,所以從盒子向匯點連費用0,流量inf的邊。

對於每一個球向每一個盒子連費用為-c(c為收益),流量為1的邊。

重點來了:怎麽處理多放?

我們已知一個公式 n^2-(n-1)^2=n*2-1;

所以我們從每一個盒子向匯點連流量為1,費用為2*n-1的邊(一共要連n-x(x為盒子的容量)次)

最後輸出-spfa_flow即可

神奇的優化:

TOP1:當前弧優化(扔了!明明跑的更慢)

TOP2:spfa優化(SLF)如果當前點的距離比隊首的距離還小就將它插入隊首

TOP3:快讀(。。。。醉了。。)

其實還有TOP0:費用流中spfa倒著做跑的更快??(學長說的玄學優化)

然後就跑的飛快啦!

再打一個多路增廣簡直快的飛起

下面貼代碼

#include<cstdio> 
#include<cstring> 
#define inf 0x3f3f3f3f 
#define r register  
#define min(a,b) (a)<(b)?(a):(b)  
#ifndef Debug 
    #define getchar() (SS==TT&&(TT=(SS=BB)+fread(BB,1,1<<15,stdin),TT==SS)?EOF:*SS++) 
    char
BB[1<<15],*SS=BB,*TT=BB; #endif inline int read(){ r int x; r bool f; r char c; for (f=0; (c=getchar())<0||c>9; f=c==-); for (x=c-0; (c=getchar())>=0&&c<=9; x=(x<<3)+(x<<1)+c-0); return f?-x:x; } using namespace std; struct
edge{ int to,next,c,w; }g[50005]; int d[501],que[5001],head[501]; bool visit[501]; int S,T,num=1; void ins(int u,int v,int c,int w){g[++num].next=head[u];head[u]=num;g[num].c=c;g[num].w=w;g[num].to=v;} void insw(int u,int v,int c,int w){ins(u,v,c,w);ins(v,u,-c,0);} bool spfa(int S,int T) { memset(visit,0,sizeof(visit)); memset(d,inf,sizeof(d)); int h=1,t=1; que[h]=T; d[T]=0; visit[T]=true; while(h<=t) { int tmp=que[h++]; for(r int i=head[tmp];i;i=g[i].next) { if(g[i^1].w&&d[tmp]-g[i].c<d[g[i].to]) { d[g[i].to]=d[tmp]-g[i].c;//d[g[i].to]=d[tmp]+g[i^1].c; if (!visit[g[i].to]) { visit[g[i].to]=true; if (d[g[i].to]<d[que[h]]) que[--h]=g[i].to;//youhua else que[++t]=g[i].to; } } }visit[tmp]=0; } return d[S]!=inf; } int dfs(int S,int T,int flow,int &ans) { visit[S]=true; if(S==T)return flow; int used=0,w; for(r int i=head[S];i;i=g[i].next) { if(!visit[g[i].to]&&g[i].w&&d[S]-d[g[i].to]==g[i].c) { if(w=dfs(g[i].to,T,min(g[i].w,flow-used),ans)) { used+=w; g[i].w-=w; g[i^1].w+=w; ans+=g[i].c*w; if(used==flow)return flow; } } } return used; } int mcf(int S,int T){ r int ans=0; while(spfa(S,T)) do memset(visit,0,sizeof(visit)); while(dfs(S,T,inf,ans)); return ans; } int main(){ r int n=read(),m=read(); S=0;T=n+m+5; r int x; for(int i=1;i<=n;i++) { x=read(); insw(S,i,0,x); insw(i,T,0,x); } for(r int i=1;i<=m;i++) { x=read(); insw(i+n,T,0,x); for(r int j=0;j<=n-x;j++)insw(i+n,T,(j<<1)|1,1); } for(r int i=1;i<=n;i++) for(r int j=1;j<=m;j++) { x=read(); insw(i,n+j,-x,1); } printf("%d\n",-mcf(S,T)); return 0; }

YYH的球盒遊戲(NOIP模擬賽Round 6)