hdu 3488

来源:互联网 发布:淘宝怎么看权重 编辑:程序博客网 时间:2024/06/03 17:43

和最少路径的覆盖差不多,先把每个点拆为两个点,分别放在x集合和y集合中,若i->j,那在图中加边xi->yj

每种方案和一个完美匹配是对应的。在完美匹配中每个点在x,y集合中的点都有相匹配的点,也就是每个点入度出度都为1.

二分图最佳完美匹配模板题,只不过求最小,把边的权值改为负数,求最大即可。

不存在的边g[][]赋值为-inf。因为是求权值最大的匹配,保证不存在的边不会选了。

#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <algorithm>#include <cmath>#include <stack>#include <vector>#define LL long long#define myabs(x) ((x)>0?(x):(-(x)))using namespace std;const int inf=0x3f3f3f3f;const int maxn=200+10;int S[maxn],T[maxn];int g[maxn][maxn];int lv[maxn],rv[maxn],leftp[maxn];int slack;int n,m;int match(int u){    S[u]=1;    int i;    for(i=1;i<=n;i++)    {        if(lv[u]+rv[i]==g[u][i])        {            if(!T[i])            {                T[i]=1;                if(leftp[i]==-1||match(leftp[i]))                {                    leftp[i]=u;                    return 1;                }            }        }        else slack=min(lv[u]+rv[i]-g[u][i],slack);    }    return 0;}void update(){    for(int i=1;i<=n;i++)    {        if(S[i]) lv[i]-=slack;        if(T[i]) rv[i]+=slack;     }}int  solve(){    int i,j;    for(i=1;i<=n;i++)    {        lv[i]=rv[i]=0;        for(j=1;j<=n;j++)            lv[i]=max(lv[i],g[i][j]);    }    for(i=1;i<=n;i++)    {        for(;;)        {            for(j=1;j<=n;j++)                 S[j]=T[j]=0;            slack=inf;            if(match(i)) break;            else update();        }    }    int sum=0;    for(i=1;i<=n;i++) sum=sum+lv[i]+rv[i];    return sum;}int main(){    int T;    cin>>T;    while(T--)    {        scanf("%d%d",&n,&m);        int i,u,v,val;        memset(g,-inf,sizeof(g));        memset(leftp,-1,sizeof(leftp));        for(i=0;i<m;i++)        {            scanf("%d%d%d",&u,&v,&val);            if(-val>g[u][v]) g[u][v]=-val;        }        int ans=-solve();        printf("%d\n",ans);    }    return 0;}


原创粉丝点击