BZOJ 1927 星际竞速
http://www.lydsy.com/JudgeOnline/problem.php?id=1927
思路:把一个点拆成两个点,
S->i 费用0,流量1 (代表这个点可以移动到其他点所必备的流量)
i+n->T 费用0,流量1 (每个点都必须要走过)
u->v+n 费用w,流量1 (代表可以移动到那个点)
S->i+n 费用a[i],流量1 (代表从这个点瞬移)
1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 int tot,go[200005],next[200005],first[200005],cost[200005],flow[200005]; 7 int op[200005],dis[200005],c[200005],vis[200005],edge[200005],from[200005]; 8 int S,T,n,m,ans; 9 int read(){ 10 char ch=getchar();int t=0,f=1; 11 while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} 12 while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} 13 return t*f; 14 } 15 void insert(int x,int y,int z,int l){ 16 tot++; 17 go[tot]=y; 18 next[tot]=first[x]; 19 first[x]=tot; 20 flow[tot]=z; 21 cost[tot]=l; 22 } 23 void add(int x,int y,int z,int l){ 24 insert(x,y,z,l);op[tot]=tot+1; 25 insert(y,x,0,-l);op[tot]=tot-1; 26 } 27 bool spfa(){ 28 for (int i=S;i<=T;i++) 29 dis[i]=0x3f3f3f3f,vis[i]=0; 30 int h=1,t=1;c[1]=S;vis[S]=1;dis[S]=0; 31 while (h<=t){ 32 int now=c[h++]; 33 for (int i=first[now];i;i=next[i]){ 34 int pur=go[i]; 35 if (dis[pur]>dis[now]+cost[i]&&flow[i]){ 36 dis[pur]=dis[now]+cost[i]; 37 edge[pur]=i; 38 from[pur]=now; 39 if (vis[pur]) continue; 40 vis[pur]=1; 41 c[++t]=pur; 42 } 43 } 44 vis[now]=0; 45 } 46 return dis[T]!=0x3f3f3f3f; 47 } 48 void updata(){ 49 int mn=0x7ffffff; 50 for (int i=T;i!=S;i=from[i]){ 51 mn=std::min(mn,flow[edge[i]]); 52 } 53 for (int i=T;i!=S;i=from[i]){ 54 ans+=mn*cost[edge[i]]; 55 flow[edge[i]]-=mn; 56 flow[op[edge[i]]]+=mn; 57 } 58 } 59 int main(){ 60 n=read();m=read(); 61 S=0;T=n+n+1; 62 for (int i=1;i<=n;i++) 63 add(S,i,1,0); 64 for (int i=1;i<=n;i++){ 65 int x=read(); 66 add(S,i+n,1,x); 67 } 68 for (int i=1;i<=n;i++) 69 add(i+n,T,1,0); 70 while (m--){ 71 int u=read(),v=read(),w=read(); 72 if (u>v) std::swap(u,v); 73 add(u,v+n,1,w); 74 } 75 ans=0; 76 while (spfa()) updata(); 77 printf("%d\n",ans); 78 }