Description
题意:给定n个点m条边的无向图,只能从编号小的到编号大的,且要求经过所有点刚好一次,而且可以从任意点瞬移到i号点并花费代价Ai,求最小代价。
n<=800,m<=15000
Solution
Code
#include#include #include #define N 2010#define Inf 0x7fffffffusing namespace std;struct info{int to,nex,f,c;}e[N*100];int n,m,T,S,tot,nodes,head[N],Ans;int dis[N],fr[N];bool vis[N];inline void Link(int u,int v,int f,int c){ e[++tot].to=v;e[tot].nex=head[u];head[u]=tot;e[tot].f=f;e[tot].c=c; e[++tot].to=u;e[tot].nex=head[v];head[v]=tot;e[tot].f=0;e[tot].c=-c;}inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}inline void Init(){ n=read(),m=read(); S=0,T=n*2+1;tot=1; for(int i=1;i<=n;++i){ int t=read(); Link(S,i,1,0); Link(i+n,T,1,0); Link(S,i+n,1,t); } while(m--){ int u=read(),v=read(),w=read(); if(u>v) swap(u,v); Link(u,v+n,1,w); }}queue q;bool spfa(){ for(int i=0;i<=T;++i)dis[i]=Inf; while(!q.empty()) q.pop(); dis[0]=0,q.push(0),vis[0]=1; while(!q.empty()){ int u=q.front();q.pop(); //vis[u]=0; for(int i=head[u];i;i=e[i].nex){ int v=e[i].to; if(e[i].f&&dis[v]>dis[u]+e[i].c){ dis[v]=dis[u]+e[i].c; fr[v]=i; if(!vis[v]){vis[v]=1;q.push(v);} } } vis[u]=0; } if(dis[T]==Inf) return 0; return 1;}void mcf(){ int x=Inf; for(int i=fr[T];i;i=fr[e[i^1].to]) x=min(x,e[i].f); for(int i=fr[T];i;i=fr[e[i^1].to]){ Ans+=x*e[i].c; e[i].f-=x; e[i^1].f+=x; }}int main(){ Init(); while(spfa()) mcf(); printf("%d\n",Ans); return 0;}