本节的主题是 flow network,只有一道题用到了朴素的最大流算法。

Drainage Ditches (ditch)

此题是一个最基本的最大流问题,可以用基于Ford-Fulkerson的Edmonds-Karp算法。

Ford-Fulkerson(G,s,t)
1 .for each edge(u,v)∈E[G]
2.     do f[u,v]=0
3.          f[v,u]=0
4.while there exists a path p from s to t in the residual network Gf
5      do cf(p)←min{ cf(u,v) : (u,v)is in p}
6.for each edge(u,v) in p
7.     do f[u,v]=f[u,v]+cf(p)
8.         f[v,u]=-f[u,v]

Edmonds-Karp
/*
ID:ryan
TASK:ditch
LANG:C
*/
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<math.h>
#define MAX 201
int q[MAX];
int min(int a,int b)
{
    
return a>b?b:a;
}
typedef 
struct
{
    
int f,c,cf;
}MAP;
MAP map[MAX][MAX];
int pre[MAX];
int best;
int m,n;
long ans;
int Init()
{
    freopen(
"ditch.in","r",stdin);
    scanf(
"%d%d",&n,&m);
    
int i,j;
    
int s,e,flow;
    
for(i=1;i<=n;i++)
    {
        scanf(
"%d%d%d",&s,&e,&flow);
        map[s][e].c
+=flow;
        map[s][e].cf
+=flow;
    }
}
int Edmonds_karp(int s,int t)
{
    
int rear,front;
    
while(1)
    {   
        
int i,j;
        rear
=0;
        front
=0;
        q[rear
++]=s;
        memset(pre,
0,sizeof(pre));
        pre[s]
=s;
        best
=0x7fffffff;
        
while(rear>front)
        {
            
int now=q[front++];
            
if(now==t)
                
break;
            
for(i=1;i<=m;i++)
            {
                
if(pre[i]==0&&map[now][i].cf>0)
                {
                    best
=min(best,map[now][i].cf);
                    pre[i]
=now;
                    q[rear
++]=i;
                }
            }
        }
        
if(pre[t]==0)
            
break;
        i
=t;
        
while(i!=s)
        {   
            map[pre[i]][i].f
+=best;
            map[i][pre[i]].f
=(-1)*map[pre[i]][i].f;
            map[pre[i]][i].cf
=map[pre[i]][i].c-map[pre[i]][i].f;
            map[i][pre[i]].cf
=map[i][pre[i]].c-map[i][pre[i]].f;
            i
=pre[i];
        }
    }
    
int i;
    
for(i=1;i<=m;i++)
    {
        
if(i!=m)
            ans
+=map[i][m].f;
    }
    
return 0;
}
int main()
{   
    freopen(
"ditch.out","w",stdout);
    Init();
    Edmonds_karp(
1,m);
    printf(
"%ld\n",ans);
    
//system("pause");
    return 0;
}


The Perfect Stall (stall4)
二分图匹配,可以用最大流做,也可以用匈牙利匹配算法。关于匈牙利匹配,详见http://www.cppblog.com/RyanWang/archive/2008/11/16/67054.html。
Hungary
#include<iostream>
using namespace std;
#define max 210
long N,M;
bool mark[max];
int v[max][max];
int mat[max];
int ans=0;
void input()
{
    freopen(
"stall4.in","r",stdin);
    freopen(
"stall4.out","w",stdout);
    cin
>>N>>M;
    
for(int i=1;i<=N;i++)
    {
        cin
>>v[i][0];
        
for(int j=1;j<=v[i][0];j++)
            cin
>>v[i][j];
    }
    memset(mark,
0,sizeof(mark));
    memset(mat,
0,sizeof(mat));
}
bool find(int k)
{
    
for(int i=1;i<=v[k][0];i++)
    {
        
int j=v[k][i];
        
if(!mark[j])
        {
        mark[j]
=1;
        
if(mat[j]==0||find(mat[j]))
        {
            mat[j]
=k;
            
return true;
        }
    }
}
return false;
}
int main()
{
    input();
    
for(int i=1;i<=N;i++)
    {
        
if(find(i))
            ans
++;
        memset(mark,
0,sizeof(mark));
    }
    cout
<<ans<<endl;
return 0;
}



Job Processing (job)
首先讲a和b分开考虑,单独用贪心算法可以分别求出单独操作a和b的最短时间------best=min(start[i]+time[i]).start[i]=best;不断更新n次。然后a中最先完成的物品放在b中操作时间最长的机器上可以达到最优策略。
CODE

#include 
<iostream>
#include 
<fstream>
using namespace std;
 
ifstream fin(
"job.in");
ofstream fout(
"job.out");
 
const long maxn=1000;
const long maxm=30;
 
long i,j; 
long n=0,m1=0,m2=0;
long mina,minia,minb,minib; 
long a[maxm],b[maxm],wa[maxm],wb[maxm],fa[maxn],fb[maxn];
 
int main(void)
{
    fin 
>>>>m1 >>m2;
    
for (i=0;i<m1;i++)
        fin 
>>a[i];
    
for (i=0;i<m2;i++)
        fin 
>>b[i]; 
 
    
for (i=0;i<n;i++)
    {
        mina
=wa[0]+a[0]; 
        minia
=0
        minb
=wb[0]+b[0]; 
        minib
=0
        
for (j=1;j<m1;j++)
            
if (mina>wa[j]+a[j])
            {
                  mina
=wa[j]+a[j]; 
                  minia
=j;
            } 
        
for (j=1;j<m2;j++)
           
if (minb>wb[j]+b[j])
           {
              minb
=wb[j]+b[j];
              minib
=j;
           }
        wa[minia]
=mina;
        fa[i]
=mina; 
        wb[minib]
=minb; 
        fb[i]
=minb;
    }
    fout 
<<mina <<' ';
    mina
=fa[0]+fb[n-1]; 
    
for (i=1;i<n;i++)
    
if (mina<fa[i]+fb[n-i-1])
        mina
=fa[i]+fb[n-i-1];
    fout 
<<mina <<endl;
 
    fin.close();
    fout.close();
 
    
return 0
}

Cowcycles (cowcycle)
qinz是这样说的:“这题很有趣,数据范围很吓人,如果无视数据范围谁都知道这是一道枚举题,重点在于计算上的一些优化。据说除法比乘法慢多了所以尽量不用除法就不要用了,而且里面会有很多重复的除法运算,所以我把数据范围可能用到的除法都先打表出来,div[i][j]=i/j,还有几个运算时用到频率特别高的常量也先计算好,如r*f、1/(r*f-1)。其中最无奈的一个优化是排序算法的选择!我用qsort在第五个数据过不去,但用冒泡居然过了,最后用sort更快,最慢的数据为0.7s(不知道这样是快是慢)。结论是,我该从qsort转移到sort了,STL确实很优秀。”