您的位置:首页 > 产品设计 > UI/UE

UVA 11324 The Largest Clique (拆点+KM)

2015-09-09 20:56 417 查看
题意:有n个盒子,围城一个环,每个盒子里可能有糖果或无糖果,总糖果不超过N,要求,把盒子中糖果数超过1的移到无糖果的盒子中,问最少几步。

分析:把有糖果数为val的盒子,拆成val个装一个糖果的盒子,编号num1从1开始累加,但他们在同一点。然后就是与每个盒子匹配,用km,这里要求最少几步,就拿距离来建图。

w[i][j] 表示第i个糖果的盒子,到第j个盒子的距离,由于是求最少,那么w[i][j]=-w[i][j],求出最大,然后答案取反就是最小。
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <string.h>
#include <map>
#include <set>
using namespace std;
const int maxn=505;
const int inff=1<<30;
int w[maxn][maxn],n,m;
int lx[maxn],ly[maxn];
int r[maxn],slack[maxn],val;
bool s[maxn],t[maxn];
bool match(int i)
{
    s[i]=true;
    for(int j=1;j<=m;j++)
    {
        int temp=lx[i]+ly[j]-w[i][j];
        if(temp==0&&!t[j])
        {
            t[j]=true;
            if(!r[j]||match(r[j]))
            {
                r[j]=i;
                return true;
            }
        }
      if(!t[j])
        slack[j]=min(slack[j],temp);
    }
    return false;
}
void update()
{
    int i,j;
    int a=inff;
  /*  for(i=1;i<=n;i++)
    {
        if(s[i])
        for(j=1;j<=m;j++)
        {
            if(!t[j])
            {
              a=min(a,lx[i]+ly[j]-w[i][j]);
            }
        }
    }*/
    for(j=1;j<=m;j++)
        if(!t[j])
         a=min(a,slack[j]);
    for(i=1;i<=n;i++)
    {
        if(s[i])lx[i]-=a;

    }
    for(j=1;j<=m;j++)
          if(t[j])ly[j]+=a;
}
void km()
{
    int i,j;
    memset(r,0,sizeof r);
    memset(lx,0,sizeof lx);
    memset(ly,0,sizeof ly);
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            lx[i]=max(lx[i],w[i][j]);
        }
    }
    for(i=1;i<=n;i++)
    {
        for( j=1;j<=m;j++)
            slack[j]=inff;
        while(1)
        {
            memset(s,0,sizeof s);
            memset(t,0,sizeof t);
             if(match(i))break;
                else update();
        }
    }
}
int x[maxn],y[maxn];
int main()
{
    int num1,num2;
    while(scanf("%d",&n)!=EOF)
    {
    /*****************************///拆点
        num1=num2=1;
        for(int i=1;i<=n;i++)
        {
           scanf("%d",&val);
           if(val)
           {
               for(int j=1;j<=val;j++)
                x[num1++]=i;
               y[num2++]=i;
           }
           else y[num2++]=i;
        }
        for(int i=1;i<num1;i++)
        {
            for(int j=1;j<num2;j++)
            {

                w[i][j]=min(max(x[i],y[j])-min(x[i],y[j]),min(x[i],y[j])+n-max(x[i],y[j]));
                if(x[i]==y[j])w[i][j]=0;
                w[i][j]=-w[i][j];
            }
        }
    /******************************/
        n=num1-1,m=num2-1;
        km();
        int ans=0;
        for(int j=1;j<=m;j++)
        {
            if(r[j])
            {
                ans+=w[r[j]][j];
            }
        }
        printf("%d\n",-ans);
    }
  return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: