您的位置:首页 > 其它

hdu3315My Brute KM算法

2015-08-07 14:53 232 查看
//starvae和xingxing各有n个小弟,每个小弟都有hp和攻击力
//对于第i个小弟,starvae小弟的攻击力为a[i] ,xingxing小弟的攻击力为b[i]
//每场比赛,starvae小弟先攻击,然后一人攻击一次,谁的血量不先大于0谁输
//starvae用第i个小弟赢了比赛得到v[i]的分数,输了减去v[i]的分数
//刚开始是starvae的第i个小弟岁星星的第i个小弟
//问在原先的比赛顺序改变最少的前提下得到的最多分数
//如果没有在原有顺序改变最少这个前提,就是一个完备图的最大权匹配
//对于顺序改变最少,由于v[i] < 1000可以将原来的边都乘以1000,然后将原先对应的边w[i][i]的权值加1
//那么最终得到的答案在除以1000就行,而且在结果相同的情况下KM必然优先选择的是原先得边
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std ;
const int maxn = 110 ;
const int inf = 0x3f3f3f3f ;
int v[maxn] ;
int w[maxn][maxn] ;int n ;
int a[maxn] , s[maxn] , p[maxn] , b[maxn] ;
int lx[maxn] , ly[maxn] , match[maxn] ;
int visx[maxn] , visy[maxn] ,slack[maxn];
bool find(int x)
{
    visx[x] = 1 ;
    for(int i = 1;i <= n;i++)
    {
        if(visy[i])continue ;
        int tmp = lx[x] + ly[i] - w[x][i] ;
        if(tmp ==0)
        {
            visy[i] = 1 ;
            if(match[i] == -1 || find(match[i]))
            {
                match[i] = x ;
                return true ;
            }
        }
        else slack[i] = min(slack[i] , tmp) ;
    }
    return false ;
}
int KM()
{
    memset(match , -1 , sizeof(match)) ;
    memset(ly , 0 , sizeof(ly)) ;
    for(int i = 1;i <= n;i++)
    {
        lx[i] = -inf ;
        for(int j = 1;j <= n;j++)
        lx[i] = max(lx[i] , w[i][j]) ;
    }
    for(int i = 1;i <= n;i++)
    {
        for(int j = 1;j <= n;j++)
        slack[j] = inf ;
        while(1)
        {
            memset(visx , 0 ,sizeof(visx)) ;
            memset(visy , 0 , sizeof(visy)) ;
            if(find(i))break ;
            int d = inf ;
            for(int j = 1;j <= n;j++)
            if(!visy[j])
            d = min(d , slack[j]) ;
            for(int j = 1;j <= n;j++)
            if(visx[j])
            lx[j] -= d ;
            for(int j = 1;j <= n;j++)
            if(visy[j])
            ly[j] += d ;
            else slack[j] -= d ;
        }
    }
    int ans = 0 ;
    for(int i = 1;i <= n;i++)
    ans += w[match[i]][i] ;
    return ans ;
}
int main()
{
    //freopen("in.txt" ,"r" , stdin) ;
    while(scanf("%d" , &n) && n)
    {
        for(int i = 1;i <= n;i++)
        scanf("%d" , &v[i]) ;
        for(int i = 1;i <= n;i++)
        scanf("%d"  ,&s[i]) ;
        for(int i = 1;i <= n;i++)
        scanf("%d" , &p[i]) ;
        for(int i = 1;i <= n;i++)
        scanf("%d" , &a[i]) ;
        for(int i = 1;i <= n;i++)
        scanf("%d" , &b[i]) ;
        for(int i = 1;i <= n;i++)
        {
            for(int j = 1;j <= n;j++)
            if((p[j] + a[i] - 1)/a[i] <= (s[i] + b[j] -1)/b[j])
               w[i][j] = v[i]*1000 ;
            else
               w[i][j] = -v[i]*1000 ;
            w[i][i] += 1;
        }
        int ans = KM() ;
        if(ans/1000 <= 0)
        puts("Oh, I lose my dear seaco!") ;
        else
        {
            printf("%d " , ans/1000) ;
            printf("%.3lf" , (double)(ans%1000)/(double)n*100.0) ;
            puts("%") ;
        }
    }
    return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: