BZOJ1266 [AHOI2006]上学路线(Dinic算法求最大流)
可可和卡卡家住合肥市的东郊,每天上学他们都要转车多次才能到达市区西端的学校。直到有一天他们两人参加了学校的信息学奥林匹克竞赛小组才发现每天上学的乘车路线不一定是最优的。 可可:“很可能我们在上学的路途上浪费了大量的时间,让我们写一个程序来计算上学需要的最少时间吧!” 合肥市一共设有N个公交车站,不妨将它们编号为1…N的自然数,并认为可可和卡卡家住在1号汽车站附近,而他们学校在N号汽车站。市内有M条直达汽车路线,执行第i条路线的公交车往返于站点pi和qi之间,从起点到终点需要花费的时间为ti。(1<=i<=M, 1<=pi, qi<=N) 两个人坐在电脑前,根据上面的信息很快就编程算出了最优的乘车方案。然而可可忽然有了一个鬼点子,他想趁卡卡不备,在卡卡的输入数据中删去一些路线,从而让卡卡的程序得出的答案大于实际的最短时间。而对于每一条路线i事实上都有一个代价ci:删去路线的ci越大卡卡就越容易发现这个玩笑,可可想知道什么样的删除方案可以达到他的目的而让被删除的公交车路线ci之和最小。 [任务] 编写一个程序: 从输入文件中读取合肥市公交路线的信息; 计算出实际上可可和卡卡上学需要花费的最少时间; 帮助可可设计一个方案,删除输入信息中的一些公交路线,使得删除后从家到学校需要的最少时间变大,而被删除路线的ci和最小;向输出文件输出答案。
Input
输入文件中第一行有两个正整数N和M,分别表示合肥市公交车站和公交汽车路线的个数。以下M行,每行(第i行,总第(i+1)行)用四个正整数描述第i条路线:pi, qi, ti, ci;具体含义见上文描述。
Output
输出文件最多有两行。 第一行中仅有一个整数,表示从可可和卡卡家到学校需要的最短时间。 第二行输出一个整数C,表示Ci之和
题解:
先按距离建图跑最短路,再按时间建图跑最大流。
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll inf=1e18; const int maxn=1e6; int N,M; int head[maxn]; int tol; struct node { int u; int v; ll w; int next; }edge[maxn]; void addedge (int u,int v,ll w) { edge[tol].u=u; edge[tol].v=v; edge[tol].w=w; edge[tol].next=head[u]; head[u]=tol++; } ll d[maxn]; int visit[maxn]; void spfa (int s) { for (int i=1;i<=N;i++) d[i]=inf; d[s]=0; queue<int> q; q.push(s); visit[s]=1; while (!q.empty()) { int u=q.front(); q.pop(); visit[u]=0; for (int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if (edge[i].w>0&&d[v]>d[u]+edge[i].w) { d[v]=d[u]+edge[i].w; if (!visit[v]) { q.push(v); visit[v]=1; } } } } } ll dep[maxn]; ll inque[maxn]; ll vi; ll cur[maxn]; ll maxflow=0; int s,t; bool bfs () { for (int i=1;i<=2*N;i++) cur[i]=head[i],dep[i]=inf,inque[i]=0; dep[s]=0; queue<int> q; q.push(s); while (!q.empty()) { int u=q.front(); q.pop(); inque[u]=0; for (int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if (dep[v]>dep[u]+1&&edge[i].w) { dep[v]=dep[u]+1; if (inque[v]==0) { q.push(v); inque[v]=1; } } } } if (dep[t]!=inf) return 1; return 0; } ll dfs (int u,ll flow) { ll increase=0; if (u==t) { vi=1; maxflow+=flow; return flow; } ll used=0; for (int i=cur[u];i!=-1;i=edge[i].next) { cur[u]=i; int v=edge[i].v; if (edge[i].w&&dep[v]==dep[u]+1) { if (increase=dfs(v,min(flow-used,edge[i].w))) { used+=increase; edge[i].w-=increase; edge[i^1].w+=increase; if (used==flow) break; } } } return used; } ll Dinic () { while (bfs()) { vi=1; while (vi==1) { vi=0; dfs(s,inf); } } return maxflow; } int u[maxn]; int v[maxn]; ll w[maxn]; ll c[maxn]; int main () { memset(head,-1,sizeof(head)); scanf("%d%d",&N,&M); for (int i=0;i<M;i++) { scanf("%d%d%lld%lld",&u[i],&v[i],&w[i],&c[i]); addedge(u[i],v[i],w[i]); addedge(v[i],u[i],w[i]); } s=1; t=N; spfa(1); printf("%lld\n",d[N]); memset(head,-1,sizeof(head)); tol=0; for (int i=0;i<M;i++) { if (d[u[i]]+w[i]==d[v[i]]) { addedge(u[i],v[i],c[i]); addedge(v[i],u[i],0); } if (d[v[i]]+w[i]==d[u[i]]) { addedge(v[i],u[i],c[i]); addedge(u[i],v[i],0); } } printf("%lld\n",Dinic()); }