费用流BZOJ1877[SDOI2009]-晨跑
Posted Yiyi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了费用流BZOJ1877[SDOI2009]-晨跑相关的知识,希望对你有一定的参考价值。
【题目大意】
Elaxia每天从寝室出发跑到学校,保证寝室编号为1,学校编号为N。 Elaxia的晨跑计划是按周期(包含若干天)进行的,由于他不喜欢走重复的路线,所以在一个周期内,每天的晨跑路线都不会相交(在十字路口处),寝室和学校不算十字路口。表示路口a和路口b之间有条长度为c的街道(单向),求出最长周期的天数和满足最长天数的条件下最短的路程长度。
【思路】
拆点。我们可以将每个路口拆成两个点(i)和(i+N)。由于Ai与Bi之间有长度为C的街道,则在(Ai)和(Bi+N)之间添加一条容量为1,费用为c的边。然后对于每个Ai,添加一条(Ai+n,Ai)的边,容量为1(保证每个路口仅仅经过一次),费用为0的边。最大流即可。
要注意的是1和N不算是路口,所以(1与n+1)(n与2n)之间的边容量为INF。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 #include<vector> 8 using namespace std; 9 const int MAXm=20000+50; 10 const int MAXn=(200+50)*2; 11 const int INF=0x7fffffff; 12 int n,m;//十字路口数和街道数 13 struct node 14 { 15 int to,cap,cost,pos; 16 }; 17 vector<node> E[MAXn]; 18 int pre[MAXn],preedge[MAXn]; 19 20 void addedge(int u,int v,int cap,int cost) 21 { 22 E[u].push_back((node){v,cap,cost,E[v].size()}); 23 E[v].push_back((node){u,0,-cost,E[u].size()-1}); 24 } 25 26 void init() 27 { 28 scanf("%d%d",&n,&m); 29 for (int i=0;i<m;i++) 30 { 31 int u,v,cost; 32 scanf("%d%d%d",&u,&v,&cost); 33 addedge(u,n+v,1,cost); 34 } 35 for (int i=2;i<=n-1;i++) addedge(n+i,i,1,0); 36 addedge(n+1,1,INF,0); 37 addedge(2*n,n,INF,0); 38 //建图的时候不要忘掉了,从1和n+1的边,n和2n的边容量为INF,否则只能跑一天! 39 } 40 41 int SPFA() 42 { 43 int dis[MAXn],vis[MAXn]; 44 for (int i=1;i<=2*n;i++) dis[i]=INF; 45 memset(vis,0,sizeof(vis)); 46 memset(pre,-1,sizeof(pre)); 47 queue<int>que; 48 que.push(1); 49 dis[1]=0; 50 vis[1]=1; 51 while (!que.empty()) 52 { 53 int head=que.front(); 54 que.pop(); 55 vis[head]=0; 56 for (int i=0;i<E[head].size();i++) 57 { 58 node& tmp=E[head][i]; 59 if (tmp.cap>0 && dis[tmp.to]>dis[head]+tmp.cost) 60 { 61 dis[tmp.to]=dis[head]+tmp.cost; 62 pre[tmp.to]=head; 63 preedge[tmp.to]=i; 64 if (!vis[tmp.to]) 65 { 66 vis[tmp.to]=1; 67 que.push(tmp.to); 68 } 69 } 70 } 71 } 72 if (dis[n]==INF) return 0;//这里是返回到n而不是2n 73 else return 1; 74 } 75 76 void mcmf() 77 { 78 int ans=0,days=0; 79 while (SPFA()) 80 { 81 days++; 82 int flow=INF; 83 for (int i=n;pre[i]!=-1;i=pre[i]) 84 flow=min(flow,E[pre[i]][preedge[i]].cap); 85 for (int i=n;pre[i]!=-1;i=pre[i]) 86 { 87 node& tmp=E[pre[i]][preedge[i]]; 88 tmp.cap-=flow; 89 E[tmp.to][tmp.pos].cap+=flow; 90 ans+=flow*tmp.cost; 91 } 92 } 93 cout<<days<<‘ ‘<<ans<<endl; 94 } 95 96 int main() 97 { 98 init(); 99 mcmf(); 100 return 0; 101 }
以上是关于费用流BZOJ1877[SDOI2009]-晨跑的主要内容,如果未能解决你的问题,请参考以下文章