本节的主题是 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 >>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确实很优秀。”
|