bzoj 1070: [SCOI2007]修车

n,m位置有毒

/**************************************************************
    Problem: 1070
    User: lxy8584099
    Language: C++
    Result: Accepted
    Time:588 ms
    Memory:4084 kb
****************************************************************/
 
/*
    费用流 。。。
    可以把每个工人拆成m个 如果走第一个表示工人第一个修这辆车 
    然后就是跑一边最小费用最大流。。。
    n 顾客 m技术人员 
*/
#include<queue>
#include<cstdio> 
#include<cstring>
using namespace std;
const int N=2050;
struct pp {int v,nxt,c,d;} e[N*100];
int n,m,st,ed,tot=1,from[N],dis[N],ans,head[N];
bool vis[N];
int min(int a,int b) {return a>b?b:a;} 
void add(int u,int v,int c,int d)
{
    e[++tot].nxt=head[u];head[u]=tot;
    e[tot].v=v;e[tot].c=c;e[tot].d=d;
    e[++tot].nxt=head[v];head[v]=tot;
    e[tot].v=u;e[tot].c=0;e[tot].d=-d;
}
bool spfa()
{
    memset(dis,0x3f,sizeof(dis)); dis[st]=0;
    queue<int> q;q.push(st);
    while(!q.empty()) 
    {
        int u=q.front();q.pop(); vis[u]=0;
        for(int j=head[u];j;j=e[j].nxt) if(e[j].c>0)
        {
            int v=e[j].v,d=e[j].d;
            if(dis[v]>dis[u]+d)
            {
                dis[v]=dis[u]+d; from[v]=j;
                if(!vis[v]) vis[v]=1,q.push(v);
            }
        }
    }
    if(dis[ed]==dis[0]) return 0;
    int mn=dis[0];
    for(int i=ed,j;i!=st;i=e[j^1].v)
        j=from[i],mn=min(mn,e[j].c);
    ans+=dis[ed]*mn;
    for(int i=ed,j;i!=st;i=e[j^1].v)
        j=from[i],e[j].c-=mn,e[j^1].c+=mn;
    return 1;
}
int main()
{
    scanf("%d%d",&m,&n);
    st=n*m+n+1;ed=st+1;
    for(int i=1;i<=n;i++) add(st,n*m+i,1,0);
    for(int i=1;i<=n*m;i++) add(i,ed,1,0);
    for(int i=1;i<=n;i++)
    for(int j=1,x;j<=m;j++) 
    {
        scanf("%d",&x);
        for(int k=1;k<=n;k++)
            add(n*m+i,(k-1)*m+j,1,x*k);
    }
    while(spfa());
    printf("%.2lf\n",(double)(ans)/n);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lxy8584099/p/10313762.html
今日推荐