题意:有n个公司,m个任务,每个公司相对应每个任务有一个效益,每个公司最初有安排一个任务,求收获最大效益时候的最小变更次数。
题解:最大流最小费的题,但是建边与以往不同,每个任务和每个公司流量均为1,限制一个公司只能完成一个任务,一个任务只能由一个公司来完成。但是变更次数的限制很难完成,所以我们就设置每个公司连接的任务的费用为-N*效益,N代表最大的任务数,建边时,若是公司最初安排的任务,则这个公司连接这个任务的费用为-N*效益-1,流量为1,
若不是则费用为-N*效益,流量为1。这样建边,最后没有变更的数是-cost%N,得到的效益为-cost/N。
AC代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
const int oo=0x7f7f7f7f; //无穷
const int mm=5505; //边
const int mn=2505; //点
int node,src,dest,edge;
int ver[mm],flow[mm],cost[mm],nex[mm];
int head[mn],dis[mn],p[mn],q[mn],vis[mn];
/**这些变量基本与最大流相同,增加了
cost 表示边的费用,
p 记录可行流上节点对应的反向边
*/
void prepare(int _node,int _src,int _dest) //预处理 点的个数 起点 终点
{
node=_node,src=_src,dest=_dest;
for(int i=0; i<node; i++)head[i]=-1,vis[i]=0;
edge=0;
}
void addedge(int u,int v,int f,int c)
{
ver[edge]=v,flow[edge]=f,cost[edge]=c,nex[edge]=head[u],head[u]=edge++;
ver[edge]=u,flow[edge]=0,cost[edge]=-c,nex[edge]=head[v],head[v]=edge++;
}
/**以上同最大流*/
/**spfa 求最短路,并用 p 记录最短路上的边*/
bool spfa()
{
int i,u,v,l,r=0,tmp;
for(i=0; i<node; ++i)dis[i]=oo;
dis[q[r++]=src]=0;
p[src]=p[dest]=-1;
for(l=0; l!=r; (++l>=mn)?l=0:l)
for(i=head[u=q[l]],vis[u]=0; i>=0; i=nex[i])
if(flow[i]&&dis[v=ver[i]]>(tmp=dis[u]+cost[i]))
{
dis[v]=tmp;
p[v]=i^1;
if(vis[v]) continue;
vis[q[r++]=v]=1;
if(r>=mn)r=0;
}
return p[dest]>-1;
}
/**源点到汇点的一条最短路即可行流,不断的找这样的可行流*/
int SpfaFlow()
{
int i,ret=0,delta;
while(spfa())
{
for(i=p[dest],delta=oo; i>=0; i=p[ver[i]])
if(flow[i^1]<delta)delta=flow[i^1];
for(i=p[dest]; i>=0; i=p[ver[i]])
flow[i]+=delta,flow[i^1]-=delta;
ret+=delta*dis[dest];
}
return ret;
}
int zuichu[55][55];
int gongsi[55];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&zuichu[i][j]);
for(int i=1;i<=n;i++)
scanf("%d",&gongsi[i]);
prepare(n+m+2,0,n+m+1);
for(int i=1;i<=n;i++)addedge(0,i,1,0);
for(int i=1;i<=m;i++)addedge(i+n,n+m+1,1,0);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(gongsi[i]==j)addedge(i,j+n,1,-100*zuichu[i][j]-1);
else addedge(i,j+n,1,-100*zuichu[i][j]);
}
int cost=SpfaFlow();
int all=0;
for(int i=1;i<=n;i++)
all+=zuichu[i][gongsi[i]];
int change=n+cost%100;
int yaoyi=-cost/100-all;
printf("%d %d\n",change,yaoyi);
}
}