BZOJ 1070: [SCOI2007]修车

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;

}

  

  

posted on 2015-04-17 00:04  forgot93  阅读(124)  评论(0编辑  收藏  举报

导航