好题,回路的问题一般都要转化为度数来做
若原图的基图不连通,或者存在某个点的入度或出度为0则无解。
统计所有点的入度出度之差di
对于di>0的点,加边(s,i,di,0);
对于di<0的点,加边(i,t,-di,0);
对原图中的每条边(i,j),在网络中加边(i,j,inf,边权),
最小费用流的解加上原图所有边权和即为答案。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 6 using namespace std; 7 struct way{int po,next,flow,cost;} e[40010]; 8 const int inf=100000007; 9 int pre[110],p[110],cur[110],d[110],fa[110],cd[110],rd[110],q[2000010]; 10 bool v[110]; 11 int n,m,len,t; 12 13 int getf(int x) 14 { 15 if (fa[x]!=x) fa[x]=getf(fa[x]); 16 return fa[x]; 17 } 18 19 bool check() 20 { 21 for (int i=1; i<=n; i++) 22 if (!rd[i]||!cd[i]||getf(i)!=getf(1)) return 0; 23 return 1; 24 } 25 26 void add(int x,int y,int f,int c) 27 { 28 e[++len].po=y; 29 e[len].flow=f; 30 e[len].cost=c; 31 e[len].next=p[x]; 32 p[x]=len; 33 } 34 35 void build(int x,int y, int f, int c) 36 { 37 add(x,y,f,c); 38 add(y,x,0,-c); 39 } 40 41 bool spfa() 42 { 43 int f=1,r=1; 44 for (int i=1; i<=t; i++) d[i]=inf; 45 memset(v,false,sizeof(v)); 46 d[0]=0; q[1]=0; 47 while (f<=r) 48 { 49 int x=q[f++]; 50 v[x]=0; 51 for (int i=p[x]; i!=-1; i=e[i].next) 52 { 53 int y=e[i].po; 54 if (e[i].flow&&d[x]+e[i].cost<d[y]) 55 { 56 d[y]=d[x]+e[i].cost; 57 pre[y]=x; cur[y]=i; 58 if (!v[y]) 59 { 60 q[++r]=y; 61 v[y]=1; 62 } 63 } 64 } 65 } 66 return d[n]<inf; 67 } 68 69 int mincost() 70 { 71 int j,s=0; 72 while (spfa()) 73 { 74 int neck=inf; 75 for (int i=t; i; i=pre[i]) 76 { 77 j=cur[i]; 78 neck=min(neck,e[j].flow); 79 } 80 s+=d[t]*neck; 81 for (int i=t; i; i=pre[i]) 82 { 83 j=cur[i]; 84 e[j].flow-=neck; 85 e[j^1].flow+=neck; 86 } 87 } 88 return s; 89 } 90 91 int main() 92 { 93 int cas; 94 scanf("%d",&cas); 95 while (cas--) 96 { 97 scanf("%d%d",&n,&m); 98 memset(p,255,sizeof(p)); len=-1; 99 memset(rd,0,sizeof(rd)); 100 memset(cd,0,sizeof(cd)); 101 for (int i=1; i<=n; i++) fa[i]=i; 102 int ans=0; 103 for (int i=1; i<=m; i++) 104 { 105 int x,y,u,v,z; 106 scanf("%d%d%d",&x,&y,&z); 107 cd[++x]++;rd[++y]++; 108 build(x,y,inf,z); 109 u=getf(x),v=getf(y); 110 if (u!=v) fa[u]=v; 111 ans+=z; 112 } 113 if (!check()) 114 { 115 puts("-1"); 116 continue; 117 } 118 t=n+1; 119 for (int i=1; i<=n; i++) 120 if (rd[i]>cd[i]) build(0,i,rd[i]-cd[i],0); 121 else build(i,t,cd[i]-rd[i],0); 122 ans+=mincost(); 123 printf("%d\n",ans); 124 } 125 }
时间: 2024-10-11 17:20:07