keyword:怎样建图?怎样转换网络流;
如果想到网络流的话 ,就知道是费用流。
然后怎么建图;
我们有以下几个说明:
1.加入源点,汇点
2.加入每个源点和顾客连线的话,add(0,x,1,0)
3:问题在于怎么在顾客和技术工人上连线:
首先 我们知道 每个顾客可以和每个工人练一天cost(i,j)的线,但是有等待时间
枚举等待时间即是在连接k*cost(i,j)的边,
但是我们不是顾客连一个工人连N条线,工人再连线到汇点,因为我们知道一个工人只能做1个k*cost(i,j),举例来说 比如x这个技术工人只能第一下连y,第二下连z;
所以一个巧妙的思路是:形成n+1 - n*m+n个新点,让1-n 个顾客 与这些点连。(其实一时半会说不出)
总而言之,我们要做到 第一个顾客选择了弟i个技术工人的话 当且仅当联系一次。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<vector>
#include<queue>
#include<map>
#define N 100000
#define inf 0x3f3f3f
using namespace std;
struct edge
{
int v,next,flow,cost,cap;
}e[N<<2];
int head[N],tot;
int pre[N],dis[N];
int vis[N];
int n,m;
int cnt;
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int cap,int cost)
{
e[tot].v=v;
e[tot].cap=cap;
e[tot].cost=cost;
e[tot].flow=0;
e[tot].next=head[u];;
head[u]=tot++;
e[tot].v=u;
e[tot].cap=0;
e[tot].cost=-cost;
e[tot].flow=0;
e[tot].next=head[v];
head[v]=tot++;
}
int spfa(int s,int t)
{
queue<int>q;
for (int i=0;i<=cnt;i++)
{
dis[i]=inf;
vis[i]=0;
pre[i]=-1;
}
dis[s]=0;
vis[s]=1;
q.push(s);
while (!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for (int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].v;
if (e[i].cap>e[i].flow&&dis[v]>dis[u]+e[i].cost)
{
dis[v]=dis[u]+e[i].cost;
pre[v]=i;
if (!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
return pre[t]!=-1;
}
int minCost(int s,int t,int &cost)
{
int flow=0;
cost=0;
while (spfa(s,t))
{
int Min=inf;
for (int i=pre[t];i!=-1;i=pre[e[i^1].v])
Min=min(Min,e[i].cap-e[i].flow);
for (int i=pre[t];i!=-1;i=pre[e[i^1].v])
{
e[i].flow+=Min;
e[i^1].flow-=Min;
cost+=e[i].cost*Min;
}
flow+=Min;
}
return flow;
}
int mp[123][123];
int main()
{
init();
scanf("%d%d",&m,&n);
int s=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
scanf("%d",&mp[i][j]);
for (int i=1;i<=n;i++)
add(s,i,1,0);
cnt=n;
for (int i=1;i<=m;i++)//主要是这里
for (int k=1;k<=n;k++)
{
++cnt;
for (int j=1;j<=n;j++)
add(j,cnt,1,k*mp[j][i]);
}
for (int i=n+1;i<=cnt;i++)
add(i,cnt+1,1,0);
cnt++;
int t=cnt;
int ans;
int flow=minCost(s,t,ans);
//printf("%d\n",ans);
printf("%.2lf\n",(double) ans/n);
return 0;
}