洛谷$P2469 [SDOI2010]$ 星际竞速 网络流

正解:网络流

解题报告:

传送门$QwQ$

题目好长昂,,,大概概括下就说有$m$条单向边,$n$个点,每条边有一条边权,每个点有一个点权,然后问每个点都要到达一遍的最小代价是多少$QwQ$?

发现有两个要求,一个是每个点恰好经过一次,一个是代价最小,不显然考虑最小费用最大流,,,?

考虑拆点呗,先给源点和入点,出点和汇点分别连上流量为1费用为0的边,然后对于跳跃操作,就给源点和出点连上流量为1费用为$a_i$的边;对于航道$(x,y)$,就从$x$的入点连向$y$的出点,$over$

昂正确性可以理解成类似于最小割的亚子,,,?

就首先每个点要么是跳过去要么是通过路走过去.

但是如果直接和$S$连路的代价$T$连跳的代价也布星,因为这样就不能保证每个点只被经过一次?就感性理解下,如果切断了两条边,但是这两条边的起点是一样的,这显然是布星的(因为每个点只能被经过一次鸭$QwQ$.

所以就考虑拆点,这样就能保证每个点最多被经过一次了$QwQ$

当然辣最后建图肯定和最小割还是有点儿差别的,,,毕竟一个费用流一个最大流显然还是不一样的鸭$QwQ$.

但我的理解来说大致思想是差不多的所以我就用最小割解释了下$QwQ$

实在不理解的自己画个图就好?$QwQ$

 

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define gc getchar()
#define t(i) edge[i].to
#define w(i) edge[i].wei
#define fy(i) edge[i].fy
#define ri register int
#define rc register char
#define rb register bool
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)
#define e(i,x) for(ri i=head[x];~i;i=edge[i].nxt)

const int N=8000+10,M=150000+10;
int n,m,ed_cnt=-1,head[N],dis[N],fr_ed[N],fr_nod[N],S,T,as;
bool vis[N];
struct ed{int to,nxt,wei,fy;}edge[M<<1];

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il void ad(ri x,ri y,ri z,ri p)
{edge[++ed_cnt]=(ed){x,head[y],z,p};head[y]=ed_cnt;edge[++ed_cnt]=(ed){y,head[x],0,-p};head[x]=ed_cnt;}
il bool spfa()
{
    queue<int>Q;Q.push(S);memset(vis,0,sizeof(vis));memset(dis,63,sizeof(dis));vis[S]=1;dis[S]=0;
    while(!Q.empty())
    {
        ri nw=Q.front();Q.pop();vis[nw]=0;
        e(i,nw)
            if(w(i) && dis[t(i)]>dis[nw]+fy(i))
            {dis[t(i)]=dis[nw]+fy(i);fr_ed[t(i)]=i;fr_nod[t(i)]=nw;if(!vis[t(i)])Q.push(t(i)),vis[t(i)]=1;}
    }
    if(dis[T]==dis[T+1])return 0;
    ri flow=dis[T+1];
    for(ri i=T;i!=S;i=fr_nod[i])flow=min(flow,w(fr_ed[i]));
    for(ri i=T;i!=S;i=fr_nod[i])w(fr_ed[i])-=flow,w(fr_ed[i]^1)+=flow;
    as+=flow*dis[T];return 1;
}


int main()
{
    //freopen("2469.in","r",stdin);freopen("2469.out","w",stdout);
    n=read();m=read();S=0;T=n<<1|1;memset(head,-1,sizeof(head));rp(i,1,n)ad(i,S,1,0),ad(T,i+n,1,0);
    rp(i,1,n)ad(i+n,S,1,read());rp(i,1,m){ri x=read(),y=read();if(x>y)swap(x,y);ad(y+n,x,1,read());}
    while(spfa());printf("%d
",as);
    return 0;
}
View Code

 

原文地址:https://www.cnblogs.com/lqsukida/p/11371866.html