hdu3488-Tour(最大权匹配变种)

来源:互联网 发布:淘宝买家信用贷款 编辑:程序博客网 时间:2024/05/21 10:03

题目来源:http://showproblem.php?pid=3488

题意

有一个有向图,图中包括一个或多个环,那么使用一个或者多个环的情况下将所有点进行覆盖,最小权值是多少。环:只有一个点经过两次,其余各点各经过一次

思路

Kuhn-Munkers算法的几种变形应用
1.Kuhn-Munkers算法是求最大权完备匹配,如果要求最小权完备匹配怎么办?方法很简单,只需将所有的边权值取其相反数,求最大权完备匹配,匹配的值再取相反数即可。
2.Kuhn-Munkers算法的运行要求是必须存在一个完备匹配,如果求一个最大权匹配(不一定完备)该如何办?依然很简单,把不存在的边权值赋为0。
3.Kuhn-Munkers算法求得的最大权匹配是边权值和最大,如果我想要边权之积最大,又怎样转化?还是不难办到,每条边权取自然对数,然后求最大和权匹配,求得的结果a再算出e^a就是最大积匹配。
以上文字来源:http://dsqiu.iteye.com/blog/1689505
目测这道题属于第一种变种。。。。
so 。。。模板躺过 。。。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=200+19;const int INF=0x3f3f3f3f;int link[maxn],v_x[maxn],v_y[maxn];int mp[maxn][maxn],slack[maxn],ex_x[maxn],ex_y[maxn];int n,w;void init(){    scanf("%d%d",&n,&w);    for(int i=1; i<=n; i++)        for(int j=1; j<=n; j++)            mp[i][j]=-INF;    for(int i=0; i<w; i++)    {        int x,y,z;        scanf("%d%d%d",&x,&y,&z);        if(mp[x][y]<-z)            mp[x][y]=-z;    }}bool dfs(int i){    v_x[i]=1;    for(int j=1; j<=n; j++)    {        if(!v_y[j])        {            int dx=ex_x[i]+ex_y[j]-mp[i][j];            if(dx==0)            {                v_y[j]=1;                if(link[j]==-1||dfs(link[j]))                {                    link[j]=i;                    return true;                }            }            else                slack[j]=min(slack[j],dx);        }    }    return false;}void solve(){    memset(link,-1,sizeof(link));    memset(ex_y,0,sizeof(ex_y));    for(int i=1; i<=n; i++)    {        ex_x[i]=-INF;//纠结了很久。。。        for(int j=1; j<=n; j++)            if(ex_x[i]<mp[i][j])                ex_x[i]=mp[i][j];    }    for(int i=1; i<=n; i++)    {        memset(slack,INF,sizeof(slack));        while(1)        {            memset(v_x,0,sizeof(v_x));            memset(v_y,0,sizeof(v_y));            if(dfs(i)) break;            int d=INF;            for(int j=1; j<=n; j++)            {                if(!v_y[j])                    d=d>slack[j]?slack[j]:d;            }            for(int j=1; j<=n; j++)            {                if(v_x[j]) ex_x[j]-=d;                if(v_y[j]) ex_y[j]+=d;                else slack[j]-=d;//因为上一句。。。            }        }    }    int sum=0;    for(int i=1; i<=n; i++)        sum+=mp[link[i]][i];    printf("%d\n",-sum);}int main(){    int T;    scanf("%d",&T);    while(T--)    {        init();        solve();    }}
原创粉丝点击