题意: 给个无向图,有重边(取最小权值即可),有n个点,要求每个点在一个环中,球最小的总权值。 因为是无向图,所有要见两条;
KM_match():
/*HDU 1853*/ #include <iostream> #include <cstdlib> #include <cstdio> #include <string> #include <cstring> #include <cmath> #include <vector> #include <queue> #include <algorithm> #include <map> using namespace std; const int maxn = 1010; const int INF = 1<<30; int n, m; int g[maxn][maxn]; int Lx[maxn], Ly[maxn]; int match[maxn]; bool fx[maxn], fy[maxn]; bool dfs(int i) { fx[i] = 1; for(int j = 1; j <= n; j++) if(Lx[i]+Ly[j] == g[i][j] && !fy[j]) { fy[j] = 1; if(match[j]==-1 ||dfs(match[j])) { match[j] = i; return 1; } } return 0; } int KM_match() { memset(match, -1, sizeof(match)); memset(Ly, 0, sizeof(Ly)); for(int i = 1; i <= n; i++) { Lx[i]=-INF ; for(int j = 1; j <= n; j++) Lx[i] = max(Lx[i], g[i][j]); } for(int k = 1; k <= n; k++) { while(1) { memset(fx,0,sizeof(fx)); memset(fy,0,sizeof(fy)); if(dfs(k)) break; int a = INF; for(int i = 1; i <= n; i++) if(fx[i]) for(int j = 1; j <= n; j++) if(!fy[j]) a = min(a, Lx[i]+Ly[j]-g[i][j]); for(int i = 1; i <= n; i++) if(fx[i]) Lx[i] -= a; for(int j = 1; j <= n; j++) if(fy[j]) Ly[j] += a; } } int ans = 0; int sum=0; for(int i = 1 ; i <= n ;i++) { if(match[i]==-1 || g[match[i]][i]==-INF) return -1 ; //没有最有匹配(完备匹配) sum += g[match[i]][i] ; } return -sum ; } int main() { int t,u,v,w; scanf("%d",&t); for(int k = 1 ; k <= t ; k++) { scanf("%d%d",&n,&m); for(int i = 1 ; i <= n ;i++) for(int j = 1 ; j <= n ;j++) g[i][j] = -INF ; while(m--) { scanf("%d%d%d",&u,&v,&w); if(g[u][v] < -w) g[u][v] =g[v][u]= -w ; //注意无向边 } int ans=KM_match(); if(ans==-1 ) printf("Case %d: NO\n",k); else printf("Case %d: %d\n",k,ans); } return 0; }
最小费用最大流:
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #define inf 99999999 using namespace std; struct node { int u,v,f,c; }; node e[60000]; int first[3000],next[60000],cc; int p[3000],preedge[3000],d[3000],ans_flow,ans_cost; inline void add_edge(int u,int v,int f,int c) { e[cc].u=u; e[cc].v=v; e[cc].f=f; e[cc].c=c; next[cc]=first[u]; first[u]=cc; cc++; e[cc].v=u; e[cc].u=v; e[cc].f=0; e[cc].c=-c; next[cc]=first[v]; first[v]=cc; cc++; } bool spfa(int s,int t) { int inq[3000]; memset(inq,0,sizeof(inq)); memset(p,-1,sizeof(p)); memset(preedge,-1,sizeof(preedge)); int i; for(i=0;i<=t;i++) d[i]=inf; d[s]=0; queue<int> q; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); inq[u]=0; for(i=first[u];i!=-1;i=next[i]) { if(e[i].f) { int v=e[i].v; if(d[v]>d[u]+e[i].c) { d[v]=d[u]+e[i].c; p[v]=u; preedge[v]=i; if(!inq[v]) { inq[v]=1; q.push(v); } } } } } if(d[t]>=inf) return false; else return true; } void min_cost_flow(int s,int t) { ans_cost=0;ans_flow=0; while(spfa(s,t)) { int u=t; int mm=inf; while(p[u]!=-1) { mm=min(mm,e[preedge[u]].f); u=p[u]; } u=t; while(p[u]!=-1) { e[preedge[u]].f-=mm; e[preedge[u]^1].f+=mm; u=p[u]; } ans_cost+=mm*d[t]; ans_flow+=mm; } } int main() { int tt; scanf("%d",&tt); int cas; for(cas=1;cas<=tt;cas++) { int n,m; scanf("%d%d",&n,&m); int i; int s=0; int t=2*n+1; memset(first,-1,sizeof(first)); memset(next,-1,sizeof(next)); cc=0; for(i=1;i<=n;i++) { add_edge(s,i,1,0); add_edge(n+i,t,1,0); } for(i=0;i<m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add_edge(u,v+n,1,w); add_edge(v,u+n,1,w); } min_cost_flow(s,t); if(ans_flow<n) printf("Case %d: NO\n",cas); else printf("Case %d: %d\n",cas,ans_cost); } return 0; }