您的位置:首页 > 其它

HDU2255二分匹配最大权值

2017-08-04 20:21 375 查看
传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。

这可是一件大事,关系到人民的住房问题啊。村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子。

另一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.由于老百姓都比较富裕,他们都能对每一间房子在他们的经济范围内出一定的价格,比如有3间房子,一家老百姓可以对第一间出10万,对第2间出2万,对第3间出20万.(当然是在他们的经济范围内).现在这个问题就是村领导怎样分配房子才能使收入最大.(村民即使有钱购买一间房子但不一定能买到,要看村领导分配的).

Input输入数据包含多组测试用例,每组数据的第一行输入n,表示房子的数量(也是老百姓家的数量),接下来有n行,每行n个数表示第i个村名对第j间房出的价格(n<=300)。

Output请对每组数据输出最大的收入值,每组的输出占一行。

Sample Input
2
100 10
15 23

Sample Output
123

一道二分匹配求最大权的模板题:

#include<stdio.h>
#include<string.h>
#include<math.h>
#define LL long long
template<class T>
LL max(T a,T b)
{
return a>b?a:b;
}
template<class T>
LL min(T a, T b)
{
return a<b?a:b;
}

const int MAX=305;
const LL INF=1e9+5;
LL nx,ny;            //二部图两个部分的大小
int linker[MAX];
LL  map[MAX][MAX];
LL  lx[MAX],ly[MAX];  //两个部分的标记数组
int slack[MAX];
bool visy[MAX],visx[MAX];   //两个dfs标记

bool Dfs(int u)                         //匈牙利匹配
{
visx[u]=1;
for(int v=1;v<=ny;v++)
{
LL temp=lx[u]+ly[v]-map[u][v];
if(!visy[v]&&temp==0)     //连通边且没走过
{
visy[v]=1;
if(linker[v]==-1||Dfs(linker[v]))
{
linker[v]=u;
return 1;
}
}
else if(temp!=0)
{
if(slack[v]>temp) slack[v]=temp;
}
}
return 0;
}
LL Find()
{
memset(linker,-1,sizeof(linker)) ;
memset(ly,0,sizeof(ly));  //初始化定点标记
for(int i=1;i<=nx;i++)
{
lx[i]=-INF;
for(int j=1;j<=ny;j++)
{
if(map[i][j]>lx[i])
lx[i]=map[i][j];
}
}
for(int i=1;i<=nx;i++)
{
for(int j=1;j<=ny;j++) slack[j]=INF;
while(true)
{
memset(visy,false,sizeof(visy));
memset(visx,false,sizeof(visx));
if(Dfs(i)) break;                   //对于每一个点去找匹配(最后形成完美匹配)

LL d=INF;                          //找到最大扩展边
for(int j=1;j<=ny;j++)
if(!visy[j])
{
if(d>slack[j]) d=slack[j];
}

for(int j=1;j<=nx;j++)                  //更新定点
if(visx[j]) lx[j]-=d;
for(int j=1;j<=ny;j++)
{
if(visy[j]) ly[j]+=d;
else slack[j]-=d;
}
}
}

LL sum=0;                                           //求和
for(int i=1;i<=ny;i++)
{
if(linker[i])
sum+=map[linker[i]][i];
}
return sum;
}
int main()
{
LL n;
while(scanf("%lld",&n)!=EOF)
{
memset(map,0,sizeof(map));
LL v;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%lld",&v);
map[i][j]=v;
}
nx=ny=n;
printf("%lld\n",Find());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: