poj 1459

来源:互联网 发布:php assert 后门 编辑:程序博客网 时间:2024/06/07 00:24

这道题是典型的最大流的问题,而我也只会EK算法,其他的不太懂,但是EK算法用不好就会超时。

开始用STL输入用cin,但是TLE,改成数组和合scanf以后还是超时,后来我发现,一个浪费时间的df,下面我已经注释。

其实EK基本上可以满足你做网络流。

 

 

#include<iostream>

#include<cstdio>

using namespace std;

 

#define MIN(a,b) a<b?a:b

#define M 110

 

int start,end;

int n,np,nc,m;

int net[M][M];

int path[M*M];

int add;

 

void init();

int bfs();

void EK();

 

void init()//初始化,增加一个源点和汇点共n+2个点

{

int i;

int u,v,w;

memset(net,0,sizeof(net));

for(i=0;i<m;i++)

{

while(getchar()!='(');

scanf("%d,%d)%d",&u,&v,&w);

net[u+1][v+1]=w;

}

for(i=0;i<np;i++)

{

while(getchar()!='(');

scanf("%d)%d",&u,&w);

net[0][u+1]=w;

}

for(i=0;i<nc;i++)

{

while(getchar()!='(');

scanf("%d)%d",&u,&w);

net[u+1][n+1]=w;

}

start=0;

end=n+1;

return;

}

 

int bfs()

{

int mark=0;

int i;

memset(path,-1,sizeof(path));

int q[1000];

int t,s;

t=0,s=-1;

//q.push(start);

q[t]=start;

path[start]=-2;

while(s!=t)//找一条到汇点的通路

{

s++;

int cur=q[s];

for(int i=0;i<=n+1;i++)

{

if(path[i]==-1&&net[cur][i]>0)

{

q[++t]=i;

path[i]=cur;

if(i==n+1)//一定记住一定要到汇点才算是一条路,否则不是,这个事你TLE的关键,瓶颈。

{

mark=1;

goto m1;

}

}

}

}

 

m1:if(mark)

   {

if(path[end]==-1)

return -1;

int min_flow=INT_MAX;

int next=end;

int pre=path[next];

while(next!=start)//求得从源点到会点最小流量

{

min_flow=MIN(min_flow,net[pre][next]);

next=pre;

pre=path[next];

}

add=min_flow;

   }

   return mark;

}

 

void EK()

{

int max_flow=0;

while(bfs())

{

max_flow+=add;

int next=end;

int pre=path[next];

while(next!=start)//更新

{

net[pre][next]-=add;

net[next][pre]+=add;

next=pre;

pre=path[next];

}

}

 

cout<<max_flow<<endl;

return;

}

 

int main()

{

while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF)

{

init();

EK();

}

return 0;

}

 

//转一篇重标记法的报告,听说这个效率很高。

#include<iostream>

#include<cstdlib>

#include<queue>

#include<string>

#include<algorithm>

using namespace std;

 

const int INF=1000000000;

const int MAXN=105;

 

int n,np,nc,m,s,t;

int a[MAXN], p[MAXN], cap[MAXN][MAXN], flow[MAXN][MAXN];               //a[i]存储的是源点s到节点i的路径上的最小残留量,因为a[i]总是整数.于是可用它来替代标记数组

 

 

int main() 

{

 

     int i,u,v,w,ans;

     queue<int>q;

     char ss[30]; 

     while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF)

     {

        memset(flow,0,sizeof(flow));

        memset(cap,0,sizeof(cap));

        ans=0;

        s=n;                                                                                //源点

        t=n+1;                                                                             //汇点

        for(i=1;i<=m;i++)                                                               //输入m条边的信息

        {

            scanf("%s",ss);

            sscanf(ss,"(%d,%d)%d",&u,&v,&w);                           //这里用sccanf来实现数字分离

            cap[u][v]=w;

        }

        for(i=1;i<=np;i++)                                                            //输入np个发电厂的信息

        {

            scanf("%s",ss);

            sscanf(ss,"(%d)%d",&v,&w);

            cap[s][v]=w;                                                               //将源点和该发电厂连接连接,并置该边的权值为该发电厂的容量

        }

        for(i=1;i<=nc;i++)                                                            //输入nc个用户的信息

        {

            scanf("%s",ss);

            sscanf(ss,"(%d)%d",&u,&w);

            cap[u][t]=w;                                                               //将该用户和汇点连接,并将该边的权值置为该用户的容量

        }

        while(1)

        {

                memset(a,0,sizeof(a));

                a[s]=INF;

                q.push(s);

                while(!q.empty())                                                 //BFS找增广路

                {

                                 u=q.front();

                                 q.pop();

                                 for(v=0;v<=t;v++)

                                   if(!a[v]&&cap[u][v]>flow[u][v])          //这里用a[v]来替代了用来标记访问的数组

                                    {

                                                  p[v]=u;                               //记录v的父亲,并加入FIFO队列

                                                  q.push(v);

                                                  a[v]=min(a[u],cap[u][v]-flow[u][v]);   //路径上的最小残量

                                    }

                }

                if(a[t]==0)                                                          //找不到,则当前流已经是最大流

                   break;

                for(u=t;u!=s;u=p[u])                                           //从汇点往回走

                {

                    flow[p[u]][u]+=a[t];                                          //更新正向流量

                    flow[u][p[u]]-=a[t];                                           //更新反向流量

                }

                ans+=a[t];                                                          //更新净流量

        }

        printf("%d/n",ans);

     }

     system("pause");

     return 0;

}

原创粉丝点击