码迷,mamicode.com
首页 > 其他好文 > 详细

YYH的球盒游戏(NOIP模拟赛Round 6)

时间:2017-06-01 19:29:54      阅读:279      评论:0      收藏:0      [点我收藏+]

标签:没有   www   lin   string   代码   printf   while   公式   char   

原题传送门

这题的算法优化真是博大精深、

具体我们一个一个来讲。

我们先看这道题的算法,(这。。裸的费用流啊。。。)

然后我们发现负边(好吧,其实没有什么用。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)

标签:没有   www   lin   string   代码   printf   while   公式   char   

原文地址:http://www.cnblogs.com/ghostfly233/p/6930202.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!