整数规划
Time Limit: 5500/5000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 566 Accepted Submission(s): 202
Problem Description
度度熊有一个可能是整数规划的问题:
给定 n×n 个整数 ai,j(1≤i,j≤n),要找出 2n 个整数 x1,x2,…,xn,y1,y2,…,yn 在满足 xi+yj≤ai,j(1≤i,j≤n) 的约束下最大化目标函数 ∑ni=1xi+∑ni=1yi,
你需要帮他解决这个整数规划问题,并给出目标函数的最大值。
Input
第一行包含一个整数 T,表示有 T 组测试数据。
接下来依次描述 T 组测试数据。对于每组测试数据:
第一行包含一个整数 n,表示该整数规划问题的规模。
接下来 n 行,每行包含 n 个整数,其中第 i 行第 j 列的元素是 ai,j。
保证 1≤T≤20,1≤n≤200,−109≤ai,j≤109(1≤i,j≤n)。
Output
对于每组测试数据,输出一行信息 “Case #x: y”(不含引号),其中 x 表示这是第 x 组测试数据,y 表示目标函数的最大值,行末不要有多余空格。
Sample Input
2
1
0
2
1 2
3 4
Sample Output
Case #1: 0
Case #2: 5
Source
2018"百度之星"程序设计大赛 - 资格赛
题意:二分最佳匹配的可行顶标
二分图的最佳完美匹配:如果二分图的每条边都有一个权(可以是负数),要求一种完备匹配方案,使得所有匹配边的权和最大,记做最佳完美匹配。
可行顶标:对于原图中的任意一个结点,给定一个函数L(node)L(node)L(node)求出结点的顶标值。我们用数组lx(x)lx(x)lx(x)记录集合XXX中的结点顶标值,用数组ly(y)ly(y)ly(y)记录集合YYY中的结点顶标值。
并且,对于原图中任意一条边edge(x,y)edge(x,y)edge(x,y),都满足lx(x)+ly(y)>=weight(x,y)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=207,NPOS=-1;
const ll INF=0x3f3f3f3f3f3f3f3f;
struct KuhnMunkres
{
int n;//左右集合点数
ll a[N][N];
ll hl[N],hr[N],slk[N];//hl hr 左边集合的期望值,右边集合的期望值
int fl[N],fr[N],vl[N],vr[N],pre[N],q[N],ql,qr;//fl fr,左右匹配对应的点 vl,vr用于bfs标记,
int check(int i)
{
if(vl[i]=1,fl[i]!=NPOS)return vr[q[qr++]=fl[i]]=1;
while(i!=NPOS)swap(i,fr[fl[i]=pre[i]]);
return 0;
}
void bfs(int s)
{
fill(slk,slk+n,INF);
fill(vl,vl+n,0);
fill(vr,vr+n,0);
q[ql=0]=s;
vr[s]=qr=1;
for(ll d;;)
{
for(; ql<qr; ++ql)
for(int i=0,j=q[ql]; i<n; ++i)
if(d=hl[i]+hr[j]-a[i][j],!vl[i]&&slk[i]>=d)
if(pre[i]=j,d)slk[i]=d;
else if(!check(i))return;
d=INF;
for(int i=0; i<n; ++i)
if(!vl[i]&&d>slk[i])d=slk[i];
for(int i=0; i<n; ++i)
{
if(vl[i])hl[i]+=d;
else slk[i]-=d;
if(vr[i])hr[i]-=d;
}
for(int i=0; i<n; ++i)
if(!vl[i]&&!slk[i]&&!check(i))return;
}
}
void ask()
{
fill(pre,pre+n,NPOS);
fill(fl,fl+n,NPOS);
fill(fr,fr+n,NPOS);
fill(hr,hr+n,0);
for(int i=0; i<n; ++i) hl[i]=*max_element(a[i],a[i]+n);
for(int j=0; j<n; ++j) bfs(j);
}
} km;
int main()
{
int n;
int QAQ,kase=0;
scanf("%d",&QAQ);
while(QAQ--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
scanf("%lld",&km.a[i][j]);
km.a[i][j]=-km.a[i][j];
}
}
km.n=n;
km.ask();
long long ans=0;
for(int i=0; i<n; ++i)
ans+=km.a[i][km.fl[i]];
printf("Case #%d: %lld\n",++kase,-ans);
}
}