UVALive 3353 Optimal Bus Route Design
二分图最大完美匹配
题目
题目给出一个带权有向图,找若干个圈,使得每个结点切好属于一个圈,并且所有圈的总长度最小,如果没有满足条件的就输出N。
思路
拆点,每个点拆成入和出。建边时比如1到2,就建1到2`。权为负的。
然后这是一个二分图图,跑二分图最大完美匹配。
注意原图不存在的边要加上,权为负无穷。
最后跑完的匹配权值要是小于等于负无穷,就是N。
代码
#include<bits/stdc++.h>
#define M(a,b) memset(a,b,sizeof(a))
typedef long long LL;
const int MAXN=207;
const int oo=0x3f3f3f3f;
using namespace std;
int w[MAXN][MAXN], x[MAXN], slack[MAXN], y[MAXN];
int prev_x[MAXN], prev_y[MAXN], son_y[MAXN], par[MAXN];
int lx, ly, pop;
///w表示带权图
///pop表示一侧点数
///返回最大完美匹配权值
///son_y表示匹配方案
void adjust(int v)
{
son_y[v]=prev_y[v];
if(prev_x[son_y[v]]!=-2)
adjust(prev_x[son_y[v]]);
}
bool fin_d(int v)
{
for(int i=1;i<=pop;i++)
{
if(prev_y[i]==-1)
{
if(slack[i]>x[v]+y[i]-w[v][i])
{
slack[i]=x[v]+y[i]-w[v][i];
par[i]=v;
}
if(x[v]+y[i]==w[v][i])
{
prev_y[i]=v;
if(son_y[i]==-1)
{
adjust(i);
return true;
}
if(prev_x[son_y[i]]!=-1) continue;
prev_x[son_y[i]]=i;
if(fin_d(son_y[i])) return true;
}
}
}
return false;
}
LL km()
{
int m=-oo;
for(int i=1;i<=pop;i++)
{
son_y[i]=-1;
y[i]=0;
}
for(int i=1;i<=pop;i++)
{
x[i]=-oo;
for(int j=1;j<=pop;j++)
x[i]=max(x[i], w[i][j]);
}
bool flag;
for(int i=1;i<=pop;i++)
{
for(int j=1;j<=pop;j++)
{
prev_x[j]=prev_y[j]=-1;
slack[j]=oo;
}
prev_x[i]=-2;
if(fin_d(i)) continue;
flag=false;
while(!flag)
{
m=oo;
for(int j=1;j<=pop;j++)
{
if(prev_y[j]==-1)
m=min(m, slack[j]);
}
for(int j=1;j<=pop;j++)
{
if(prev_x[j]!=-1)
x[j]-=m;
if(prev_y[j]!=-1)
y[j]+=m;
else slack[j]-=m;
}
for(int j=1;j<=pop;j++)
{
if(prev_y[j]==-1&&!slack[j])
{
prev_y[j]=par[j];
if(son_y[j]==-1)
{
adjust(j);
flag=true;
break;
}
prev_x[son_y[j]]=j;
if(fin_d(son_y[j]))
{
flag=true;
break;
}
}
}
}
}
LL ans=0;
for(int i=1;i<=pop;i++)
ans+=w[son_y[i]][i];
return ans;
}
int main()
{
//printf("%d\n",oo);
int n;
while(scanf("%d",&n)==1&&n)
{
pop=n;
memset(w,0xc1,sizeof(w));
for(int i=1;i<=n;i++)
{
while(1)
{
int u,v;scanf("%d",&u);
if(u==0) break;
scanf("%d",&v);
w[i][u]=-v;
}
}
LL res=km();
if(res<=-99000) printf("N\n");
else printf("%lld\n",-res);
}
return 0;
}