正解:网络流
解题报告:
题目好长昂,,,大概概括下就说有$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; }