给定m个序列,每个长度为n,每个序列都是n的一个排列
求一个序列,使得这个序列和现有的m个序列的距离和最小,且这个序列也是n的一个排列,输出距离和的最小值
两个序列之间的距离定义为,这两个序列对应的每一个位置上的元素的差的绝对值的和
费用流模板题
建图:1~n代表n个位置,n+1~2n代表n个数字。每个位置到每个数子都有一条流量为1的边,代表选定这个数字,费用为在这个位置选这个数字产生的距离。源到每个位置都有一条流量为1费用为0的边。每个数字到汇都有一条流量为1费用为0的边。整个图的最小费用即为所求结果。
#include <cstring>
#include <cstdio>
const int MAXINT=(1<<30);
struct MinCostFlow {
static const int MAXNODE=2100;
static const int MAXEDGE=50000;
struct Node {
int fe,c,f,fromNode,curCost,fromEdge;
bool inque;
};
struct Edge {
int f,t,ne,c;
};
Node a[MAXNODE];
Edge b[MAXEDGE*2];
int d[MAXNODE];
int s,t,n,p,cost;
void clear(int nn,int ss,int tt) {
n=nn;s=ss;t=tt;
for (int i=0;i<=n;i++) {
a[i].fe=-1;
a[i].f=0;
a[i].c=0;
}
p=0;
cost=0;
}
void putedge(int x,int y,int f,int c) {
b[p].ne=a[x].fe;
b[p].t=y;
b[p].f=f;
b[p].c=c;
a[x].fe=p;
p++;
b[p].ne=a[y].fe;
b[p].t=x;
b[p].f=0;
b[p].c=-c;
a[y].fe=p;
p++;
}
bool spfa() {
int i,p,q,j;
for (i=0;i<=n;i++) {
a[i].curCost=MAXINT;
a[i].fromNode=-1;
a[i].fromEdge=-1;
a[i].inque=false;
}
p=q=0;
d[q++]=s;
a[s].inque=true;
a[s].curCost=0;
while (p!=q) {
i=d[p];
for (j=a[i].fe;j!=-1;j=b[j].ne) {
if (b[j].f>0&&b[j].c+a[i].curCost<a[b[j].t].curCost) {
a[b[j].t].curCost=a[i].curCost+b[j].c;
a[b[j].t].fromNode=i;
a[b[j].t].fromEdge=j;
if (a[b[j].t].inque==false) {
a[b[j].t].inque=true;
d[q]=b[j].t;
q=(q+1)%MAXNODE;
}
}
}
a[i].inque=false;
p=(p+1)%MAXNODE;
}
if (a[t].curCost==MAXINT) return false;
p=MAXINT;
q=0;
for (i=t;i!=s;i=a[i].fromNode) {
d[q++]=i;
if (p>b[a[i].fromEdge].f) p=b[a[i].fromEdge].f;
}
j=0;
for (i=q-1;i>=0;i--) {
j+=b[a[d[i]].fromEdge].c*p;
b[a[d[i]].fromEdge].f-=p;
b[a[d[i]].fromEdge^1].f+=p;
a[d[i]].c+=j;
a[d[i]].f+=p;
}
return true;
}
void flow() {
int i;
a[s].f=MAXINT;
while (spfa()) ;
}
int getFlow() {
return a[t].f;
}
int getCost() {
return a[t].c;
}
};
MinCostFlow c;
int n,m;
int a[100][100];
int abs(int x) {
return x>0?x:-x;
}
int cal(int j,int v) {
int ans=0;
for (int i=0;i<m;i++) ans+=abs(a[i][j]-v);
return ans;
}
int main() {
int i,j,x,y,z,t,tt;
scanf("%d",&t);
for (tt=1;tt<=t;tt++) {
scanf("%d%d",&n,&m);
c.clear(n+n+2,0,n+n+1);
for (i=0;i<m;i++) {
for (j=0;j<n;j++) {
scanf("%d",&a[i][j]);
}
}
for (i=0;i<n;i++) {
for (j=0;j<n;j++) {
c.putedge(i+1,j+n+1,1,cal(i,j+1));
}
}
for (i=0;i<n;i++) {
c.putedge(0,i+1,1,0);
c.putedge(i+n+1,n+n+1,1,0);
}
c.flow();
printf("Case #%d: %d\n",tt,c.getCost());
}
return 0;
}