题目大意:
给定一个无向图,顶点数为 N(N<=100) ,边数为 M(M<=1000) ,每条边有一个非负的权值,要你求出一个边权和最小的最小路径覆盖。
解题思路:
不说什么了,最小费用最大流,直接裸上就行了,有一个问题就是输出,坑了我一个小时啊,输出要求对于每条路径从起点输出到终点,而不能乱序输出路径上的点。
AC代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
int N,M;
struct bian_
{
int aim;
int next;
}bian[4010]={{0,0}};
int G[210][210]={{0}};
int F[210][210]={{0}};
int cost[210][210]={{0}};
int dui[4010]={0};
int duip=0;
int dist[210]={0};
int fa[210]={0};
int st=0,en=0;
int hash[210]={0};
int First[210]={0};
int bp=0;
int son[210]={0};
bool SPFA()
{
memset(dist,0x3f3f3f3f,sizeof(dist));
duip=0;
dist[0]=0;
dui[++duip]=0;
fa[0]=0;
hash[0]=1;
for(int i=1;i<=duip;i++)
{
int u=dui[i];
for(int p=First[u];p!=0;p=bian[p].next)
{
int v=bian[p].aim;
if(G[u][v]-F[u][v]==0) continue;
if(dist[v]>dist[u]+cost[u][v])
{
fa[v]=u;
dist[v]=dist[u]+cost[u][v];
if(hash[v]==0)
{
hash[v]=1;
dui[++duip]=v;
}
}
}
hash[u]=0;
}
if(dist[en]==0x3f3f3f3f) return false;
return true;
}
void dfs(int k)
{
if(k==0) return;
dfs(fa[k]);
F[fa[k]][k]++;
F[k][fa[k]]--;
return;
}
void Add(int p,int q)
{
bp++;
bian[bp].next=First[p];
bian[bp].aim=q;
First[p]=bp;
return;
}
int main()
{
scanf("%d%d",&N,&M);
en=N*2+1;
for(int i=1;i<=M;i++)
{
int p,q,r;
scanf("%d%d%d",&p,&q,&r);
cost[p][q+N]=r;
cost[q+N][p]=-r;
G[p][q+N]=1;
Add(p,q+N);
Add(q+N,p);
}
for(int i=1;i<=N;i++)
{
Add(0,i);
Add(i,0);
Add(i+N,en);
Add(en,i+N);
G[0][i]=G[i+N][en]=1;
}
int ans=0;
int num=0;
for(;SPFA();)
{
ans+=dist[en];
dfs(en);
num++;
}
cout<<N-num<<' '<<ans<<endl;
memset(fa,-1,sizeof(fa));
memset(son,-1,sizeof(son));
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
if(F[i][j+N]==1)
{
son[i]=j;
fa[j]=i;
}
for(int i=1;i<=N;i++)
{
if(hash[i]==1 || fa[i]!=-1) continue;
int prt[110]={0};
int ss=0;
for(int j=i;j!=-1;)
{
hash[j]=1;
prt[++ss]=j;
j=son[j];
}
printf("%d ",ss);
for(int j=1;j<=ss;j++) printf("%d ",prt[j]);
puts("");
}
return 0;
}