HDU 2426 Interesting Housing Problem(二分割図最適マッチ)


HDU 2426 Interesting Housing Problem(二分割図最適マッチ)
http://acm.hdu.edu.cn/showproblem.php?pid=2426
件名:
       N人の学生とM部屋があります.各学生は複数の部屋を採点します.もし点数>=0なら、彼はこの部屋を選ぶことができます.
       今お聞きしたいのですが、学生一人に部屋を分けてもらい、各部屋に最大一人の学生がいます.これらの部屋は全部学生が採点した部屋で、点数>0の部屋ですか?出力点数と最大値がある場合、出力-1が存在しない場合.
分析:
       まず、N>Mが出力されると、−1が直接出力されることが明らかである.
       次の場合はN<=Mの時です.まず学生は彼が採点した部屋と点数>=0の部屋しか選べないということに注意します.
       最適整合用のKMアルゴリズムを要求するので、点セットサイズ非対称KMアルゴリズムテンプレートを使用し、最適整合のためにすべての辺に権利が必要です.
       私たちはもともと存在していない辺に対して負の無限値を与えます.最良のマッチングを求めた時、もしある一致辺の権利値が負の無限であれば、この問題を解決しないことを表します.さもなければ、総合的な権利値は最適なマッチングの権利解です.
ACコード:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 1e9
using namespace std;
const int maxn=500+10;

struct Max_Match
{
    int n,m,W[maxn][maxn];
    int Lx[maxn],Ly[maxn];
    bool S[maxn],T[maxn];
    int left[maxn];

    bool match(int i)
    {
        S[i]=true;
        for(int j=1;j<=m;j++)if(Lx[i]+Ly[j]==W[i][j] && !T[j])
        {
            T[j]=true;
            if(left[j]==-1 || match(left[j]))
            {
                left[j]=i;
                return true;
            }
        }
        return false;
    }

    void update()
    {
        int a=1<<30;
        for(int i=1;i<=n;i++)if(S[i])
        for(int j=1;j<=m;j++)if(!T[j])
            a = min(a, Lx[i]+Ly[j]-W[i][j]);

        for(int i=1;i<=n;i++)if(S[i]) Lx[i]-=a;
        for(int j=1;j<=m;j++)if(T[j]) Ly[j]+=a;
    }

    int solve(int n,int m)
    {
        this->n=n;
        this->m=m;
        memset(left,-1,sizeof(left));
        memset(Lx,0,sizeof(Lx));
        memset(Ly,0,sizeof(Ly));
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            Lx[i]=max(Lx[i],W[i][j]);

        for(int i=1;i<=n;i++)
        {
            while(true)
            {
                memset(S,0,sizeof(S));
                memset(T,0,sizeof(T));
                if(match(i)) break;
                else update();
            }
        }

        int ans=0;
        for(int i=1;i<=m;i++)if(left[i]!=-1)
        {
            if(W[left[i]][i] != -INF)
                ans += W[left[i]][i];
            else return -1;
        }
        return ans;
    }
}KM;


int main()
{
    int n,m,e,kase=0;
    while(scanf("%d%d%d",&n,&m,&e)==3)
    {
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            KM.W[i][j]=-INF;

        for(int i=0;i<e;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            ++u,++v;
            if(w>=0) KM.W[u][v]=w;
        }

        printf("Case %d: %d
",++kase,KM.solve(n,m)); } return 0; }