【费用流】BZOJ1927-[Sdoi2010]星际竞速

【题目大意】

有一些点,它们之间存在一些有向边(由编号小的到编号大的),从一点到另一点消耗时间为边长。也可以消耗Ti时间直接抵达任意一个点。问所有点都走一遍最少需要多少时间?

【思路】

①将每个点i拆为i和i’。

②由S向i连(cap=1,cost=0)的边。由i'向T连(1,0)的边,表示抵达过该点。

③由S向i'连(1,Ti)的边,表示直接从某点跳转到i点。

④根据有向边[i,j]连(i,j')的边。

为什么这样是正确的?由于我们只关心每个点都被抵达过而不关心路径。费用流的前提是最大流,我们一定可以保证所有点都被经过,那么就可以通过③④区分是用跳转抵达还是通过有向边抵达了。

*好久不写费用流,华丽写挂一发。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<vector>
  6 #include<queue>
  7 #define S 0
  8 #define T 2*n+1
  9 using namespace std;
 10 const int INF=0x7fffffff;
 11 const int MAXN=(800+50)*2+1;
 12 struct node
 13 {
 14     int to,pos,cap,cost;
 15 };
 16 int n,m;
 17 vector<node> E[MAXN];
 18 int pre[MAXN],preedge[MAXN];
 19 
 20 void addedge(int u,int v,int w,int cos)
 21 {
 22     E[u].push_back((node){v,E[v].size(),w,cos});
 23     E[v].push_back((node){u,E[u].size()-1,0,-cos});
 24 }
 25 
 26 void init()
 27 {
 28     scanf("%d%d",&n,&m);
 29     for (int i=1;i<=n;i++)
 30     {
 31         int ai;
 32         scanf("%d",&ai);
 33         addedge(S,i+n,1,ai);
 34         addedge(S,i,1,0);
 35         addedge(i+n,T,1,0);
 36     }
 37     for (int i=0;i<m;i++)
 38     {
 39         int ui,vi,wi;
 40         scanf("%d%d%d",&ui,&vi,&wi);
 41         if (ui>vi) swap(ui,vi);
 42         addedge(ui,vi+n,1,wi);
 43     }
 44 }
 45 
 46 int spfa()
 47 {
 48     queue<int> que;
 49     int vis[MAXN],in[MAXN],dis[MAXN];
 50     memset(in,0,sizeof(in));
 51     memset(pre,-1,sizeof(pre));
 52     for (int i=S;i<=T;i++) dis[i]=INF;
 53     que.push(S);
 54     vis[S]=1;
 55     dis[S]=0;
 56     while (!que.empty())
 57     {
 58         int head=que.front();que.pop();
 59         vis[head]=0;
 60         for (int i=0;i<E[head].size();i++)
 61         {
 62             node &tmp=E[head][i];
 63             if (tmp.cap>0 && dis[tmp.to]>dis[head]+tmp.cost)
 64             {
 65                 dis[tmp.to]=dis[head]+tmp.cost;
 66                 pre[tmp.to]=head;
 67                 preedge[tmp.to]=i;
 68                 if (!in[tmp.to])
 69                 {
 70                     que.push(tmp.to);
 71                     in[tmp.to]=0;
 72                 }
 73             }
 74         }
 75     }
 76     if (dis[T]==INF) return 0;else return 1;
 77     //和dinic不同,不能再tmp.to==T时直接返回,因为要找到最短路 
 78 } 
 79 
 80 void mcf()
 81 {
 82     int ans=0;
 83     while (spfa())
 84     {
 85         int flow=INF; 
 86         for (int i=T;pre[i]!=-1;i=pre[i])
 87         {
 88             flow=min(flow,E[pre[i]][preedge[i]].cap);
 89         }
 90         for (int i=T;pre[i]!=-1;i=pre[i])
 91         {
 92             node& tmp=E[pre[i]][preedge[i]];
 93             tmp.cap-=flow;
 94             E[tmp.to][tmp.pos].cap+=flow;
 95             ans+=flow*tmp.cost;
 96         }
 97     }
 98     printf("%d",ans);
 99 }
100 
101 int main()
102 {
103     init();
104     mcf();
105 }

 

posted @ 2016-08-14 15:56  iiyiyi  阅读(143)  评论(0编辑  收藏  举报