[Sdoi2010]星际竞速

个人对山东省选已经十分无语了,做了三道题,都TM是费用流,这山东省选是要干什么,2009--2011连续三年,只要会费用流,然后建个边,跑一跑就过了。

10 年一度的银河系赛车大赛又要开始了。作为全银河最盛大的活动之一,夺得这个项目的冠军无疑是很多人的梦想,来自杰森座 α星的悠悠也是其中之一。

赛车大赛的赛场由 N 颗行星和M条双向星际航路构成,其中每颗行星都有一个不同的引力值。大赛要求车手们从一颗与这 N 颗行星之间没有任何航路的天体出发,访问这 N 颗行星每颗恰好一次,首先完成这一目标的人获得胜利。
由于赛制非常开放,很多人驾驶着千奇百怪的自制赛车来参赛。这次悠悠驾驶的赛车名为超能电驴,这是一部凝聚了全银河最尖端科技结晶的梦幻赛车。作为最高科技的产物,超能电驴有两种移动模式:高速航行模式和能力爆发模式。在高速航行模式下,超能电驴会展开反物质引擎,以数倍于光速的速度沿星际航路高速航行。在能力爆发模式下,超能电驴脱离时空的束缚,使用超能力进行空间跳跃——在经过一段时间的定位之后,它能瞬间移动到任意一个行星。
天不遂人愿,在比赛的前一天,超能电驴在一场离子风暴中不幸受损,机能出现了一些障碍:在使用高速航行模式的时候,只能由每个星球飞往引力比它大的星球,否则赛车就会发生爆炸。
尽管心爱的赛车出了问题,但是悠悠仍然坚信自己可以取得胜利。他找到了全银河最聪明的贤者——你,请你为他安排一条比赛的方案,使得他能够用最少的时间完成比赛。

输入描述 Input Description

第一行是两个正整数 N, M。
第二行 N 个数 A1~AN, 其中Ai表示使用能力爆发模式到达行星 i 所需的定位
时间。
接下来 M行,每行 3个正整数ui, vi, wi,表示在编号为 ui和vi的行星之间存在一条需要航行wi时间的星际航路。
输入数据已经按引力值排序,也就是编号小的行星引力值一定小,且不会有两颗行星引力值相同。

输出描述 Output Description

仅包含一个正整数,表示完成比赛所需的最少时间。

样例输入 Sample Input

3 3
1 100 100
2 1 10
1 3 1
2 3 1

样例输出 Sample Output

12

数据范围及提示 Data Size & Hint

对于 30%的数据 N≤20,M≤50;
对于 70%的数据 N≤200,M≤4000;
对于100%的数据N≤800, M≤15000。输入数据中的任何数都不会超过10^6。

这道题,个人看到双向边以后一般不会往网络流那个方向去考虑,因为网络流一般是单向边,但是不要忘了题目中已经红字标出那句话,这句话将双向边,转化为了单向边,

编号大的无法到达编号小的点,这就十分好了,因为每个星球只能经过一次,所以裂点,经过这个星球的方式有两种,分别是通过能力爆发模式和高速航行模式来到达,这样

建立一个S,和T,将每个点i裂成i和i+n两个节点。

使S与所有i+n连一条边,边权为能力爆发转移到该星球的费用。

然后使S与所有i连一条边,流量为1,因为每个星球只能经过一次,以此如果有边来到达其它星球。

然后加入的双向通道,以u与v+n连边(u<v)边的花费为边权,然后流量为1。

最后只需所有i+n与T连一条费用为0,流量为1的边即可,表示每个点最多只能为终点增加为1的流量。

这类题目,十分巧妙,主要考虑不到如何建图,考虑到了以后,题目就十分明朗了,裸裸的跑一次什么网络流就好了。

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cmath>
  4 #include<iostream>
  5 #include<cstring>
  6 #include<queue>
  7 using namespace std;
  8 
  9 const int INF=1e9+7,NN=807*2+7,MM=100007;
 10 
 11 int n,m,S,T;
 12 int cnt,head[NN],next[MM],rea[MM],val[MM],cost[MM];
 13 int dis[NN],flag[NN];
 14 struct Node
 15 {
 16     int e,fa;
 17     void init(){e=fa=-1;}
 18 }pre[NN];
 19 
 20 void add(int u,int v,int fee,int fare)
 21 {
 22     cnt++;
 23     next[cnt]=head[u];
 24     head[u]=cnt;
 25     rea[cnt]=v;
 26     val[cnt]=fee;
 27     cost[cnt]=fare;
 28 }
 29 bool Spfa()
 30 {
 31     for (int i=1;i<=T;i++)
 32     {
 33         flag[i]=0;
 34         dis[i]=INF;
 35         pre[i].init();
 36     }
 37     dis[S]=0,flag[S]=1;
 38     queue<int>q;
 39     while (!q.empty()) q.pop();
 40     q.push(S);
 41     while(!q.empty())
 42     {
 43         int u=q.front();
 44         q.pop();
 45         for (int i=head[u];i!=-1;i=next[i])
 46         {
 47             int v=rea[i],fee=cost[i];
 48             if ((dis[u]+fee<dis[v])&&val[i]>0)
 49             {
 50                 dis[v]=dis[u]+fee;
 51                 pre[v].fa=u,pre[v].e=i;
 52                 if (flag[v]==0)
 53                 {
 54                     flag[v]==1;
 55                     q.push(v);
 56                 }
 57             }
 58         }
 59         flag[u]=0;
 60     }
 61     if (dis[T]!=INF) return 1;
 62     else return 0;
 63 }
 64 void MFMC()
 65 {
 66     int Flow=0,Cost=0;
 67     while (Spfa())
 68     {
 69         int x=INF;
 70         for (int i=T;pre[i].fa!=-1;i=pre[i].fa)
 71         {
 72             int e=pre[i].e;
 73             x=min(x,val[e]);
 74         }
 75         Flow+=x,Cost+=x*dis[T];
 76         for (int i=T;pre[i].fa!=-1;i=pre[i].fa)
 77         {
 78             int e=pre[i].e;
 79             val[e]-=x,val[e^1]+=x;
 80         }
 81     }
 82     printf("%d
",Cost);
 83 }
 84 int main()
 85 {
 86     cnt=1;
 87     memset(head,-1,sizeof(head));
 88     scanf("%d%d",&n,&m);
 89     S=n*2+1,T=n*2+2;
 90     int x,y,z;
 91     for (int i=1;i<=n;i++)
 92     {
 93         scanf("%d",&x);
 94         add(S,i+n,1,x),add(i+n,S,0,-x);
 95         add(S,i,1,0),add(i,S,0,0);
 96         add(i+n,T,1,0),add(T,i+n,0,0);
 97     }
 98     for (int i=1;i<=m;i++)
 99     {
100         scanf("%d%d%d",&x,&y,&z);
101         if (x>y) swap(x,y);
102         add(x,y+n,1,z),add(y+n,x,0,-z);
103     }
104     MFMC();
105 }
原文地址:https://www.cnblogs.com/fengzhiyuan/p/7235834.html