【费用流】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 }

 

posted @ 2016-03-06 09:53  iiyiyi  阅读(198)  评论(0编辑  收藏  举报