题目链接:
题意:一个有向图。选择最少的路径覆盖所有点。在路径最少的情况下,使得所有路径经过的边的权值之和最小。
思路:没有权值的话就是一个最小路径覆盖。将每个点拆成两个点放在左右两个集合里,求最大匹配。然后怎么构造出最小路径呢?从右边没有被匹配的点开始沿着自己的匹配向下同时将与自己有边的删掉,度数为0时入栈。现在有了权值,还是求最小权值。KM可以求最大权。这时将每条边用INF-原来的权值代替。再跑KM。最后得到的路径就是最小权值的路径。
#include #include #include #include #include #include #include #include #include #include #include
> ans;stack
st;int find(int u){ fx[u]=1; int v; for(v=1;v<=n;v++) if(!fy[v]&&g[u][v]==Lx[u]+Ly[v]) { fy[v]=1; if(match[v]==-1||find(match[v])) { match[v]=u; return 1; } } return 0;}void DFS(int u,vector
&path){ int v; for(v=1;v<=n;v++) { if(p[u]!=v&&g[u][v]>0&&--d[v]==0) { st.push(v); } } d[u]=-1; path.pb(u); if(g[u][p[u]]==0) return; sum+=INF-g[u][p[u]]; DFS(p[u],path);}int main(){ RD(n,m); int i,j,u,v,c; FOR1(i,m) { RD(u,v,c); g[u][v]=INF-c; Lx[u]=max(Lx[u],g[u][v]); d[v]++; } clr(match,-1); FOR1(u,n) { while(1) { clr(fx,0); clr(fy,0); if(find(u)) break; c=INF; FOR1(i,n) if(fx[i]) FOR1(j,n) if(!fy[j]) { c=min(c,Lx[i]+Ly[j]-g[i][j]); } FOR1(i,n) { if(fx[i]) Lx[i]-=c; if(fy[i]) Ly[i]+=c; } } } FOR1(i,n) p[match[i]]=i; FOR1(i,n) if(!d[i]) st.push(i); vector
path; while(!st.empty()) { u=st.top(); st.pop(); path.clear(); DFS(u,path); ans.pb(path); } printf("%d %d\n",SZ(ans),sum); FOR0(i,SZ(ans)) { printf("%d",SZ(ans[i])); FOR0(j,SZ(ans[i])) printf(" %d",ans[i][j]); puts(""); } return 0;}