HDOJ 2813 - One fihgt one KM求最小权最大匹配..

                    题意:

                            告诉吕布的将军和曹操的将军PK某些对能赢..并且要付出一些HP的损失..问要让吕布的将军每轮都获胜..消耗的最小血量是多少..

                    题解:

                            用最小费用最大流做无限TLE...只能用KM搞了...把值置为相反数..结果取反就求除了最小权最大匹配...


Program:

#include<iostream>    
#include<algorithm>    
#include<stdio.h>    
#include<string.h>   
#include<map> 
#include<math.h>    
#include<queue>    
#define MAXN 1205  
#define MAXM 8000005    
#define oo 1000000007    
#define ll long long    
using namespace std;      
//--------------------n为两侧的个数..w[][]为关系矩阵初始为-inf-------------------   
int n;    
int linker[MAXN],lx[MAXN],ly[MAXN],slack[MAXN];    
int visx[MAXN],visy[MAXN],w[MAXN][MAXN];    
int v[MAXN],h[MAXN],p[MAXN],a[MAXN],b[MAXN];      
int DFS(int x){    
    visx[x]=1;    
    for(int y=1;y<=n;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 取最小的    
            slack[y]=tmp;    
        }    
    }    
    return 0;    
}      
int KM(){    
    int i,j;    
    memset(linker,-1,sizeof(linker));    
    memset(ly,0,sizeof(ly));    
    for(i=1;i<=n;i++)      //lx初始化为与它关联边中最大的    
        for(j=1,lx[i]=-oo;j<=n;j++)    
            if(w[i][j]>lx[i])    
                lx[i]=w[i][j];    
    for(int x=1;x<=n;x++){    
        for(i=1;i<=n;i++)    
            slack[i]=oo;    
        while(1){    
            memset(visx,0,sizeof(visx));    
            memset(visy,0,sizeof(visy));    
            if(DFS(x)) break;    
            int d=oo;    
            for(i=1;i<=n;i++)    
                if(!visy[i] && d>slack[i])    
                    d=slack[i];    
            for(i=1;i<=n;i++)    
                if(visx[i])    
                    lx[i]-=d;    
            for(i=1;i<=n;i++)    
                if(visy[i])    
                    ly[i]+=d;    
                else    
                    slack[i]-=d;    
        }    
    }    
    int res=0;    
    for(i=1;i<=n;i++){    
        if(linker[i]==-1 || w[linker[i]][i]==-oo) continue;
        res+=w[linker[i]][i];    
    }    
    return res;    
}     
//--------------------------------------------------------  
struct node
{
      int son[65],w;
}A[100005];
int num,m;
int trie(char *ss,int tp)
{
      int i,h=0,x,len=strlen(ss);
      for (i=0;i<len;i++)
      {
              if (ss[i]>='A' && ss[i]<='Z') x=ss[i]-'A';
                                      else  x=ss[i]-'a'+27;
              if (!A[h].son[x]) A[h].son[x]=++num;  
              h=A[h].son[x];
      }
      if (A[h].w) return A[h].w;
      if (tp==1) return A[h].w=++n;
      return A[h].w=++m;      
}
char ss[25];
int main()   
{           
      int i,j,N,M,k,x,y,d,Af,Ac; 
      while (~scanf("%d%d%d",&N,&M,&k))
      {
               n=m=num=0; 
               memset(A,0,sizeof(A)),N=max(N,M);
               for (i=1;i<=N;i++)
                  for (j=1;j<=N;j++)
                     w[i][j]=-oo;
               while (k--)
               {
                        scanf("%s",ss),x=trie(ss,1);
                        scanf("%s",ss),y=trie(ss,2);       
                        scanf("%d",&d); 
                        w[x][y]=-d;
               } 
               n=max(n,m);
               printf("%d\n",-KM());
      }
      return 0;  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值