zoukankan      html  css  js  c++  java
  • poj 2195 二分图最优匹配 或 最小费用最大流

    就是最基本的二分图最优匹配,将每个人向每个房子建一条边,权值就是他们manhattan距离。然后对所有权值取反,求一次最大二分图最优匹配,在将结果取反就行了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define Maxn 110
    using namespace std;
    int n;//点的数目
    int lx[Maxn],ly[Maxn]; //顶点标号
    int weight[Maxn][Maxn];// 边的权值
    int slack[Maxn];// Y(i)的松弛函数
    int sx[Maxn],sy[Maxn]; //标记X,Y中的顶点是否在交错路径上
    int match[Maxn];//Y的匹配
    struct Point{
        int x,y;
    }house[Maxn],man[Maxn];
    int Dis(Point a,Point b)
    {
        return abs(a.x-b.x)+abs(a.y-b.y);
    }
    int dfs(int u)
    {
        sx[u]=1;
        int i;
        for(i=1;i<=n;i++)
        {
            if(!sy[i]&&lx[u]+ly[i]==weight[u][i])//如果在相等子图中,且未被访问
            {
                sy[i]=1;
                if(match[i]==-1||dfs(match[i]))
                {
                    match[i]=u;
                    return 1;
                }
            }
            else
            if(!sy[i])//Y(i)不在交错路径当中
                slack[i]=min(slack[i],lx[u]+ly[i]-weight[u][i]);
        }
        return 0;
    }
    int bestmatch(bool f)
    {
        int i,j;
        if(!f)
        {
            for(i=1;i<=n;i++)
            {
                lx[i]=-0x7FFFFFFF;
                ly[i]=0;
                for(j=1;j<=n;j++)
                {
                    weight[i][j]=-weight[i][j];
                    lx[i]=max(lx[i],weight[i][j]);
                }
            }
        }
        else
        {
            for(i=1;i<=n;i++)
            {
                lx[i]=0;
                ly[i]=0;
                for(j=1;j<=n;j++)
                    lx[i]=max(lx[i],weight[i][j]);
            }
        }
        memset(match,-1,sizeof(match));
        for(i=1;i<=n;i++)
        while(1)
        {
            memset(sx,0,sizeof(sx));
            memset(sy,0,sizeof(sy));
            for(j=0;j<=Maxn-1;j++)
                slack[j]=0x7FFFFFFF;
            if(dfs(i))
                break;
            int dx=0x7FFFFFFF;
            for(j=1;j<=n;j++)
                dx=min(dx,slack[j]);
            for(j=1;j<=n;j++)
            {
                if(sx[j])
                    lx[j]-=dx;
                if(sy[j])
                    ly[j]+=dx;
            }
        }
        int ans=0;
        for(i=1;i<=n;i++)
            ans+=weight[match[i]][i];
        if(!f)
            ans=-ans;
        return ans;
    }
    int main()
    {
        int i,j,N,M,a,b;
        char str[110];
        while(scanf("%d%d",&N,&M),N||M)
        {
            a=b=0;
            for(i=1;i<=N;i++)
            {
                scanf("%s",&str);
                for(j=0;j<M;j++)
                {
                    if(str[j]=='H')
                        house[++a].x=i,house[a].y=j;
                    if(str[j]=='m')
                        man[++b].x=i,man[b].y=j;
                }
            }
            n=a;
            for(i=1;i<=n;i++)
            {
                for(j=1;j<=n;j++)
                    weight[i][j]=Dis(man[i],house[j]);
            }
            printf("%d
    ",bestmatch(false));
        }
        return 0;
    }
    View Code

     最小费油最大流解法:

    #include<iostream>
    #include<cstring>
    #include<cstring>
    using namespace std;
    const int size = 1010;
    const int INF = 0x7fffffff;
    struct Point{
        int x,y;
    };
    struct Edge
    {
        int to;
        int vol;
        int cost;
        int next;
    }e[size*100];
    Point house[110],man[110];
    int index[size];
    int edgeNum;
    int pre[size], pos[size];
    int dis[size], que[size*10];
    bool vis[size];
    void insert(int from, int to, int vol, int cost)
    {
        e[edgeNum].to = to;
        e[edgeNum].vol = vol;
        e[edgeNum].cost = cost;
        e[edgeNum].next = index[from];
        index[from] = edgeNum++;
        e[edgeNum].to = from;
        e[edgeNum].vol = 0;
        e[edgeNum].cost = -cost;
        e[edgeNum].next = index[to];
        index[to] = edgeNum++;
    }
    int DIS(Point p1,Point p2)
    {
        return abs(p1.x-p2.x)+abs(p1.y-p2.y);
    }
    bool spfa(int s, int t)
    {
        int i;
        memset(pre, -1, sizeof(pre));
        memset(vis, 0, sizeof(vis));
        int head, tail; head = tail = 0;
        for(i = 0; i < size; i++)
            dis[i] = INF;
        que[tail++] = s;
        pre[s] = s;
        dis[s] = 0;
        vis[s] = 1;
        while(head != tail)
        {
            
            int now = que[head++];
            vis[now] = 0;
            for(i = index[now]; i != -1; i = e[i].next)
            {
                int adj = e[i].to;
                if(e[i].vol > 0 && dis[now] + e[i].cost < dis[adj])
                {
                    dis[adj] = dis[now] + e[i].cost;
                    pre[adj] = now;
                    pos[adj] = i;
                    if(!vis[adj])
                    {
                        vis[adj] = 1;
                        que[tail++] = adj;
                    }
                }
            }
        }
        return pre[t] != -1;
    }
    int MinCostFlow(int s, int t, int flow)
    {
        int i;
        int cost = 0;
        flow = 0;
        while(spfa(s, t))
        {
            int f = INF;
            for(i = t; i != s; i = pre[i])
                if (e[pos[i]].vol < f) f = e[pos[i]].vol;
            flow += f; cost += dis[t] * f;
            for(i = t; i != s; i = pre[i])
            {
                e[pos[i]].vol -= f;
                e[pos[i] ^ 1].vol += f;
            }
        }
        return cost; // flow是最大流值
    }
    int main()
    {
        int n,m,i,j,u,v;
        char c;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            if(n==0&&m==0)
                break;
            memset(index,-1,sizeof(index));
            int k1=0,k2=0;
            for(i=1;i<=n;i++)
            {    
                for(j=1;j<=m;j++)
                {    
                    cin>>c;
                    switch(c)
                    {
                    case '.':break;
                    case 'm':man[++k1].x=i,man[k1].y=j;break;
                    case 'H':house[++k2].x=i,house[k2].y=j;break;
                    }
                }
            }
            for(i=1;i<=k1;i++)
            {    for(j=1;j<=k2;j++)
                {
                    insert(i,j+k1,1,DIS(man[i],house[j]));
                }
                insert(0,i,1,0);
                insert(i+k1,k1+k2+1,1,0);
            }
            //spfa(0,k1+k2+1);
            int ans=MinCostFlow(0,k1+k2+1,0);
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    抓住大数据的3个核心点 走在爆款前面
    小白学数据分析--回归分析在游戏人气分析的应用探索
    小白学数据分析--回归分析在游戏人气分析的应用探索
    Linux,unix,cygwin,centeros下的tar压缩解压缩命令具体解释
    二:Java之异常处理
    BEGINNING SHAREPOINT&#174; 2013 DEVELOPMENT 第14章节--使用Office Services开发应用程序 WOPI和新的Office Web Apps Server
    Git 的BUG小结
    android:json解析的两个工具:Gson和Jackson的使用小样例
    Cocos2d-x3.0终于版Mac以及Win系统相关环境部署
    第五十六题(最长公共子串)
  • 原文地址:https://www.cnblogs.com/wangfang20/p/3195438.html
Copyright © 2011-2022 走看看