6 9 1 2 5 2 3 5 3 1 10 3 4 12 4 1 8 4 6 11 5 4 7 5 6 9 6 5 4 6 5 1 2 1 2 3 1 3 4 1 4 5 1 5 6 1
42 -1HintIn the first sample, there are two cycles, (1->2->3->1) and (6->5->4->6) whose length is 20 + 22 = 42.
之后让这n个点组成多个环 使得每个点只能在一个环中 每个环最少2个点
求满足上面时 所有环的周长的和最小是多少
思路:
如果几个点构成一个环的话,那么这每一个点的入度与出度都是为1的 根据此 构造网络流图
设一个源点0,汇点2*n+1,源点连接每一个u,容量为1,费用为0;汇点连接每一个v+n,容量也为1,费用为0;从u到v建一条边,容量为1,费用为w;那么这就转换成了最小费用最大流的模板题,假设最后最大流为n,那么说明恰好每一个点都是入度出度为1,即构成了环。
#include <stdio.h> #include <iostream> #include <string.h> #include<cmath> using namespace std; const int N=300; const int MAXE=200000; const int inf=1<<30; int head[N],ep; int d[N],pre[N]; bool vis[N]; int q[MAXE]; struct Edge { int u,v,c,w,next; }edge[MAXE]; void addedge(int u,int v,int w,int c)//u v 费用 容量 { edge[ep].u=u; edge[ep].v=v; edge[ep].w=w; edge[ep].c=c; edge[ep].next=head[u]; head[u]=ep++; edge[ep].v=u; edge[ep].u=v; edge[ep].w=-w; edge[ep].c=0; edge[ep].next=head[v]; head[v]=ep++; } int SPFA(int src,int des) { int l,r; memset(pre,-1,sizeof(pre)); memset(vis,0,sizeof(vis)); for(int i=0;i<=des;i++) d[i]=inf; d[src]=0; l=0;r=0; q[r++]=src; vis[src]=1; while(l<r) { int u=q[l++]; vis[u]=0; for(int j=head[u];j!=-1;j=edge[j].next) { int v=edge[j].v; if(edge[j].c>0&&d[u]+edge[j].w<d[v]) { d[v]=d[u]+edge[j].w; pre[v]=j; if(!vis[v]) { vis[v]=1; q[r++]=v; } } } } if(d[des]==inf) return 0; return 1; } int flow; int MCMF(int src,int des) { flow=0;int ans=0; while(SPFA(src,des)) { ans+=d[des]; int u=des; int mini=inf; while(u!=src) { if(edge[pre[u]].c<mini) mini=edge[pre[u]].c; u=edge[pre[u]].u; } flow+=mini; u=des; while(u!=src) { edge[pre[u]].c-=mini; edge[pre[u]^1].c+=mini; u=edge[pre[u]].u; } } return ans; } int main() { int n,m,i,src,des; while(scanf("%d%d",&n,&m)!=EOF) { ep=0; memset(head,-1,sizeof(head)); src=0; des=2*n+1; while(m--) { int v1,v2,w; scanf("%d %d %d",&v1,&v2,&w); addedge(v1,v2+n,w,1); } for(i=1;i<=n;i++) { // addedge(i,i+n,0,1); addedge(src,i,0,1); addedge(i+n,des,0,1); } int ans=MCMF(src,des); if(flow==n) printf("%d\n",ans); else printf("-1\n"); } return 0; }