本节的主题是
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]
The Perfect Stall (stall4)
二分图匹配,可以用最大流做,也可以用匈牙利匹配算法。关于匈牙利匹配,详见http://www.cppblog.com/RyanWang/archive/2008/11/16/67054.html。
Job Processing (job)
首先讲a和b分开考虑,单独用贪心算法可以分别求出单独操作a和b的最短时间------best=min(start[i]+time[i]).start[i]=best;不断更新n次。然后a中最先完成的物品放在b中操作时间最长的机器上可以达到最优策略。
Cowcycles (cowcycle)
qinz是这样说的:“这题很有趣,数据范围很吓人,如果无视数据范围谁都知道这是一道枚举题,重点在于计算上的一些优化。据说除法比乘法慢多了所以尽量不用除法就不要用了,而且里面会有很多重复的除法运算,所以我把数据范围可能用到的除法都先打表出来,div[i][j]=i/j,还有几个运算时用到频率特别高的常量也先计算好,如r*f、1/(r*f-1)。其中最无奈的一个优化是排序算法的选择!我用qsort在第五个数据过不去,但用冒泡居然过了,最后用sort更快,最慢的数据为0.7s(不知道这样是快是慢)。结论是,我该从qsort转移到sort了,STL确实很优秀。”
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;
}
/*
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;
}
#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 >>n >>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;
}
#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 >>n >>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确实很优秀。”