注意题意为先满足第一种操作总花费时间最小,在进行第二次操作并满足总时间最小。 两次二分图最大权匹配,第一次从工人到沙发连边,权值为第一次操作花费时间,第二次从沙发到工人连边,权值为工人开始工作的时间加上第二次操作的时间。 本人采用费用流写法,最后从残余网络找到答案。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
using namespace std;
const int inf=1010101010;
int S,T;
int a[60][60];
int b[60][60];
int n;
struct Edge
{
int v,c,w,next;
}e[2000000];
int head[30000],cnt;
void addedge(int u,int v,int c,int w)
{
e[cnt].v=v;
e[cnt].c=c;
e[cnt].w=w;
e[cnt].next=head[u];
head[u]=cnt++;
e[cnt].v=u;
e[cnt].c=0;
e[cnt].w=-w;
e[cnt].next=head[v];
head[v]=cnt++;
}
int dis[100010];
bool vis[1010];
int pre[100010];
int pos[100010];
int mcmf()
{
int ans=0; int maxflow=0;
while(1){
for(int i=0;i<=T;i++) dis[i]=inf,vis[i]=0,pre[i]=i,pos[i]=0;
queue<int> q;
dis[S]=0;
q.push(S);
vis[S]=1;
int u,v,w,c;
while(!q.empty())
{
u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=e[i].next)
{
v=e[i].v;
if(e[i].c>0&&dis[v]>dis[u]+e[i].w)
{
pre[v]=u;
pos[v]=i;
dis[v]=dis[u]+e[i].w;
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
if(dis[T]==inf) break;
int sum=inf;
for(u=T;u!=S;u=pre[u])
{
c=e[pos[u]].c;
sum=min(sum,c);
}
maxflow+=sum;
for(u=T;u!=S;u=pre[u])
{
e[pos[u]].c-=sum;
e[pos[u]^1].c+=sum;
ans+=sum*e[pos[u]].w;
}
}
return ans;
}
int ans1[60];
int ans2[60];
vector<int> wo[60];
int main()
{
int cas=1;
while(~scanf("%d",&n))
{
if(n==0)return 0;
memset(head,-1,sizeof(head));
cnt=0;
for(int i=1;i<=n;i++)
wo[i].clear();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&b[i][j]);
S=n+n+1;
T=S+1;
for(int i=1;i<=n;i++)
{addedge(S,i,1,0);addedge(i+n,T,1,0);}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
addedge(i,j+n,1,a[i][j]);
}
}
mcmf();
for(int i=1+n;i<=n+n;i++)
{
for(int j=head[i];j!=-1;j=e[j].next)
{
if(e[j].c>0)
{
int v=e[j].v;
//cout<<v<<" ll"<<endl;
wo[v].push_back(i-n);
ans1[i-n]=v;
ans2[v]=i-n;
}
}
}
memset(head,-1,sizeof(head));cnt=0;
S=n+n+1;
T=S+1;
for(int i=1;i<=n;i++)
addedge(S,i,1,0);
for(int i=n+1;i<=n+n;i++)
addedge(i,T,1,0);
int tmp=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
tmp=max(a[ans1[i]][i],a[j][ans2[j]]);
addedge(i,n+j,1,tmp+b[j][i]);
}
}
mcmf();int sum=0;
for(int i=1+n;i<=n+n;i++)
{
for(int j=head[i];j!=-1;j=e[j].next)
{
if(e[j].c>0)
{
int v=e[j].v;
wo[i-n].push_back(v);
int w=-e[j].w;
wo[i-n].push_back(w);
//cout<<i-n<<" "<<ans2[i-n]<< " "<<wo[i-n][1]<<endl;
if(w>a[i-n][ans2[i-n]]+b[i-n][wo[i-n][1]])
sum+=w-a[i-n][ans2[i-n]]-b[i-n][wo[i-n][1]];
//ans1[i-n]=v;
//ans2[v]=i-n;
}
}
}
printf("Case %d:\n",cas++);
for(int i=1;i<=n;i++)
{
printf("Worker %d: %d %d %d\n",i,wo[i][0],wo[i][1],wo[i][2]);
}printf("Total idle time: %d\n",sum);
}
}