HDU 2853 && HDU 3315

http://acm.hdu.edu.cn/showproblem.php?pid=2853

题意:给一个n-m二分图,边权用一个n*m的矩阵表示,给出初始匹配,求二分图完美匹配相比初始匹配改变了几条边以及改变的数值

这类题的主要思想是增加原配边的权值,但又不影响最后结果。

步骤1:观察顶点数,每条边乘一个大于顶点数的数v

步骤2:对于原配边,每边加1(注意步骤2可以保证km()/v的结果与原结果相同)

步骤3:求完美匹配,答案为res,改变的边数=n-res%v(res%v表示完美匹配中有多少边属于原匹配),要求的完美匹配答案=res/v

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

const int N=310;

const int INF=0x3f3f3f3f;

int nx,ny;

int linker[N],lx[N],ly[N],slack[N];  

int visx[N],visy[N],w[N][N];

int DFS(int x)

{

    visx[x]=1;

    for(int y=1;y<=ny;y++){

        if(visy[y])

            continue;

        int tmp=lx[x]+ly[y]-w[x][y];

        if(tmp==0){

            visy[y]=1;

            if(linker[y]==-1 || DFS(linker[y])){

                linker[y]=x;

                return 1;

            }

        }else if(slack[y]>tmp){ 

            slack[y]=tmp;

        }

    }

    return 0;

}

int change ;

int KM()

{

    int i,j;

    memset(linker,-1,sizeof(linker));

    memset(ly,0,sizeof(ly));

    for(i=1;i<=nx;i++)      

        for(j=1,lx[i]=-INF;j<=ny;j++)

            if(w[i][j]>lx[i])

                lx[i]=w[i][j];

    for(int x=1;x<=nx;x++){

        for(i=1;i<=ny;i++)

            slack[i]=INF;

        while(1){

            memset(visx,0,sizeof(visx));

            memset(visy,0,sizeof(visy));

            if(DFS(x))  

                break;  

            int d=INF;

            for(i=1;i<=ny;i++)

                if(!visy[i] && d>slack[i])

                    d=slack[i];

            for(i=1;i<=nx;i++)

                if(visx[i])

                    lx[i]-=d;

            for(i=1;i<=ny;i++) 

                if(visy[i])

                    ly[i]+=d;

                else

                    slack[i]-=d;

        }

    }

    int res=0;

    for(i=1;i<=ny;i++)

        if(linker[i]!=-1)

            res+=w[linker[i]][i];

    change=nx-res%200 ;

    return res/200;

}

int main()

{

    while(~scanf("%d%d",&nx,&ny))

    {

        for(int i=1;i<=nx;i++)

            for(int j=1;j<=ny;j++)

            {

                scanf("%d",&w[i][j]);

                w[i][j]*=200 ;

            }

        int res=0 ;

        for(int i=1 ;i<=nx ;i++)

        {

            int x ;

            scanf("%d",&x) ;

            res+=w[i][x] ;

            w[i][x]++ ;

        }

        int ans=KM();

        printf("%d %d\n",change,ans-res/200);

    }    

    return 0;

}
View Code

http://acm.hdu.edu.cn/showproblem.php?pid=3315

与2853一样思路的题目,区别是这题图没有直接给,要先算一下

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

const int N=310;

const int INF=0x3f3f3f3f;

int n,nx,ny;

int linker[N],lx[N],ly[N],slack[N];  

int visx[N],visy[N],w[N][N];

int DFS(int x)

{

    visx[x]=1;

    for(int y=1;y<=ny;y++){

        if(visy[y])

            continue;

        int tmp=lx[x]+ly[y]-w[x][y];

        if(tmp==0){

            visy[y]=1;

            if(linker[y]==-1 || DFS(linker[y])){

                linker[y]=x;

                return 1;

            }

        }else if(slack[y]>tmp){ 

            slack[y]=tmp;

        }

    }

    return 0;

}

int change ;

int KM()

{

    int i,j;

    memset(linker,-1,sizeof(linker));

    memset(ly,0,sizeof(ly));

    for(i=1;i<=nx;i++)      

        for(j=1,lx[i]=-INF;j<=ny;j++)

            if(w[i][j]>lx[i])

                lx[i]=w[i][j];

    for(int x=1;x<=nx;x++){

        for(i=1;i<=ny;i++)

            slack[i]=INF;

        while(1){

            memset(visx,0,sizeof(visx));

            memset(visy,0,sizeof(visy));

            if(DFS(x))  

                break;  

            int d=INF;

            for(i=1;i<=ny;i++)

                if(!visy[i] && d>slack[i])

                    d=slack[i];

            for(i=1;i<=nx;i++)

                if(visx[i])

                    lx[i]-=d;

            for(i=1;i<=ny;i++) 

                if(visy[i])

                    ly[i]+=d;

                else

                    slack[i]-=d;

        }

    }

    int res=0;

    for(i=1;i<=ny;i++)

        if(linker[i]!=-1)

            res+=w[linker[i]][i];

    if(res<=0)return -1 ;

    change=nx-res%200 ;

    return res/200;

}

int V[N],H1[N],A1[N],H2[N],A2[N] ;

int main()

{

    while(~scanf("%d",&n),n)

    {

        nx=ny=n ;

        for(int i=1 ;i<=n ;i++)

            scanf("%d",&V[i]) ;

           for(int i=1 ;i<=n ;i++)

               scanf("%d",&H1[i]) ;

        for(int i=1 ;i<=n ;i++)

               scanf("%d",&H2[i]) ;

        for(int i=1 ;i<=n ;i++)

               scanf("%d",&A1[i]) ;

        for(int i=1 ;i<=n ;i++)

               scanf("%d",&A2[i]) ;

        for(int i=1;i<=n;i++)

            for(int j=1;j<=n;j++)

            {

                int x ;

                x=H1[i]/A2[j] ;

                if(H1[i]%A2[j])x++ ;

                if(x*A1[i]>=H2[j])w[i][j]=V[i]*200 ;

                else w[i][j]=(-V[i]*200) ;

            }

        for(int i=1 ;i<=n ;i++)

            w[i][i]++ ;

        int ans=KM();

        if(ans==-1)puts("Oh, I lose my dear seaco!") ;

        else printf("%d %.3lf%%\n",ans,(nx-change)*100.0/n);

    }    

    return 0;

}
View Code

 

你可能感兴趣的:(HDU)