每个点可以由a[i],走边 两种形式到达。于是拆点,在右边直连汇点,和连图中的边,从而表达了“或”的含义。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> #define maxv 1650 #define maxe 500500 #define inf 2000000000 using namespace std; int n,m,a[maxv],x,y,z,nume=1,g[maxv],s,t; int dis[maxv],prev[maxv],pree[maxv]; bool vis[maxv]; queue <int> q; struct edge { int v,f,c,nxt; }e[maxe]; void addedge(int u,int v,int f,int c) { e[++nume].v=v;e[nume].f=f;e[nume].c=c;e[nume].nxt=g[u];g[u]=nume; e[++nume].v=u;e[nume].f=0;e[nume].c=-c;e[nume].nxt=g[v];g[v]=nume; } bool spfa() { for (int i=s;i<=t;i++) {vis[i]=false;dis[i]=inf;prev[i]=pree[i]=-1;} vis[s]=true;dis[s]=0;q.push(s); while (!q.empty()) { int head=q.front();q.pop();vis[head]=false; for (int i=g[head];i;i=e[i].nxt) { int v=e[i].v; if ((e[i].f>0) && (dis[v]>dis[head]+e[i].c)) { dis[v]=dis[head]+e[i].c; prev[v]=head;pree[v]=i; if (!vis[v]) {vis[v]=true;q.push(v);} } } } if (dis[t]==inf) return false; return true; } int dinic() { int u=t,dt=inf; while (u!=s) { dt=min(dt,e[pree[u]].f); u=prev[u]; } u=t; while (u!=s) { e[pree[u]].f-=dt;e[pree[u]^1].f+=dt; u=prev[u]; } return dis[t]*dt; } int main() { scanf("%d%d",&n,&m);s=0;t=2*n+1; for (int i=1;i<=n;i++) { scanf("%d",&a[i]); addedge(s,i,1,0); addedge(i+n,t,1,0); addedge(s,i+n,1,a[i]); } for (int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); if (x>y) swap(x,y); addedge(x,y+n,1,z); } int min_cost=0; while (spfa()) min_cost+=dinic(); printf("%d\n",min_cost); return 0; }