POJ 2195

it2022-05-08  11

//题目类型:二分匹配-最小权完美匹配//算法实现:可以采用KM算法或者最小费用最大流实现//KM算法实现 #include <iostream>#include <string>#include <math.h>//#include <conio.h>using namespace std;#define arraysize 105int maxData = 1000000000;     int w[arraysize][arraysize];int match[arraysize];int lx[arraysize],ly[arraysize],slack[arraysize];bool finalx[arraysize],finaly[arraysize];int hcount,mcount;      //由题目可知,hcount=mcount,所以直接使用KM算法进行最大权完美匹配 typedef struct house{    int row;    int col;}house;typedef struct littleman{    int row;    int col;}littleman;littleman mans[arraysize];house houses[arraysize];bool DFS(int p){     int i,j,t;     finalx[p] = true;     for(i=1;i<=hcount;++i)     {         if(finaly[i]) continue;         int temp = lx[p]+ly[i]-w[p][i];         if(temp==0)         {             finaly[i] = true;             t = match[i];             match[i] = p;             if(t==0 || DFS(t))  return true;             match[i] = t;         }         else if(slack[i]>temp)         {             slack[i] = temp;         }     }     return false;}int KM(){    int i,j;    memset(ly,0,sizeof(ly));    memset(match,0,sizeof(match));    for(i=1;i<=mcount;++i)    {        lx[i]=-maxData;        for(j=1;j<=hcount;++j)        {            if(lx[i]<w[i][j])                lx[i] = w[i][j];        }    }    for(i=1;i<=mcount;++i)    {        for(j=1;j<=hcount;++j) slack[j] = maxData;        while(1)        {            memset(finalx,0,sizeof(finalx));            memset(finaly,0,sizeof(finaly));            if(DFS(i)) break;            int d = maxData;            for(j=1;j<=hcount;++j)            {                if(!finaly[j] && d>slack[j])                   d = slack[j];            }            for(j=1;j<=mcount;++j)            {                if(finalx[j])  lx[j]-= d;                if(finaly[j])  ly[j]+= d;                else  slack[j] -= d;                               }        }    }     int ans= 0;    for(i=1;i<=mcount;++i)    {        ans -=(lx[i]+ly[i]);   //结果加的权值需要取反     }       return ans;}int main(){    //freopen("1.txt","r",stdin);    int i,j;    int n,m;    string tempstr;    while(cin>>n>>m)    {        if(n==0 && m==0)            break;        hcount = 0;        mcount = 0;        for(i=1;i<=n;++i)        {            cin>>tempstr;            for(j=0;j<tempstr.size();++j)                        {                if(tempstr[j]=='H')                {                    hcount++;                    houses[hcount].row = i;                    houses[hcount].col = j+1;                   }                else if(tempstr[j]=='m')                {                    mcount++;                    mans[mcount].row = i;                    mans[mcount].col = j+1;                }            }              }        for(i=1;i<=mcount;++i)        {            for(j=1;j<=hcount;++j)            {                //KM算法求的是最大权的完美匹配,所以将权值取反,权值是距离                 w[i][j] = -(abs(mans[i].row-houses[j].row)+abs(mans[i].col-houses[j].col));             }        }        cout<<KM()<<endl;    }    //getch();    return 0;}

//使用最小费用最大流实现 //本题的关键在于建图:将小人和房间都作为图中的点,并设置一超级源点和超级终点,小人和房间的容量设置为1,费用设置为距离。源点到小人//的容量设置为1,费用为0;房间到终点的容量设置为1,费用设置为0 #include <iostream>#include <string>//#include <conio.h>#include <queue>#include <math.h>using namespace std;#define arraysize 205typedef struct house{    int row;    int col;}house;typedef struct littleman{    int row;    int col;}littleman;house houses[101];littleman mans[101];int n,m; int mcount,hcount;int maxData = 10000000;int capacity[arraysize][arraysize];int kcost[arraysize][arraysize];bool final[arraysize];       //SPFA算法中标识结点是否在队列中 int d[arraysize];int flow[arraysize][arraysize];int pre[arraysize];int ncount;      

void SPFA(int src){    queue<int> myqueue;    int i,j;    memset(final,0,sizeof(final));    memset(pre,-1,sizeof(pre));    myqueue.push(src);    for(i=0;i<=ncount;++i)      //SPFA算法与Dij不同,SPFA初始化时将除源点以外所有点的最短距离初始化无穷大,ncount为结点总数    {        d[i] = maxData;    }    d[src] = 0;        //源点最短距离设置成0     final[src] = true;    while(!myqueue.empty())     //SPFA算法可入队列多次     {        int frontint = myqueue.front();myqueue.pop();        final[frontint] = false;        for(i=0;i<=ncount;++i)        {            if(capacity[frontint][i]>flow[frontint][i] && d[i]>d[frontint]+kcost[frontint][i])     //c[u][v]>f[u][v]说明<u,v>之间流量可以进行增加             {                d[i] = d[frontint]+kcost[frontint][i];                pre[i] = frontint;             //修改前驱                 if(!final[i])                {                    final[i] = true;                    myqueue.push(i);                }            }        }    }}void minCost(int src,int des){    int minAdd = maxData;    int p;    while(1)    {        SPFA(src);        if(pre[des]==-1)           //表示已无增广路            break;        minAdd = maxData;        p = des;        while(pre[p]!=-1)        {            minAdd = min(minAdd,(capacity[pre[p]][p]-flow[pre[p]][p])); //求的增广路的可增流量             p = pre[p];        }        p = des;        while(pre[p]!=-1)         //沿着最小费用路进行增广         {            flow[pre[p]][p] += minAdd;            flow[p][pre[p]] -= minAdd;            p = pre[p];        }        }    }int main(){    //freopen("1.txt","r",stdin);    int i,j;    int src,des;    int flowcost;    string tempstr;    while(cin>>n>>m)    {        if(n==0 && m==0)            break;         flowcost = 0;   //最小费用         mcount = 0;  //小人的数目         hcount = 0;  //房间的数目         memset(kcost,0,sizeof(kcost));         memset(capacity,0,sizeof(capacity));          memset(flow,0,sizeof(flow));           for(i=1;i<=n;++i)        {            cin>>tempstr;            for(j=0;j<tempstr.size();++j)            {                if(tempstr[j]=='H')                {                     hcount++;                     houses[hcount].row = i;                     houses[hcount].col = j+1;                             }                else if(tempstr[j]=='m')                {                     mcount++;                     mans[mcount].row = i;                     mans[mcount].col = j+1;                }            }            }        //小人和房间之间构图         for(i=1;i<=mcount;++i)        {            for(j=1;j<=hcount;++j)            {                kcost[i][j+mcount] = abs(mans[i].row-houses[j].row)+abs(mans[i].col-houses[j].col); //费用设置为距离                 kcost[j+mcount][i] = -kcost[i][j+mcount];                          capacity[i][j+mcount] = 1;                                     }        }        src = 0;        des = hcount+mcount+1;         ncount = hcount+mcount+2;     //结点总数        //源点到小人之间构图         for(i=1;i<=mcount;++i)        {            capacity[src][i] = 1;        }        //房间到终点之间构图         for(j=1;j<=hcount;++j)        {            capacity[j+mcount][des] = 1;        }        minCost(src,des);        for(i=1;i<=mcount;++i)        {            for(j=1;j<=hcount;++j)            {                flowcost += kcost[i][j+mcount]*flow[i][j+mcount]; //最小费用             }        }         cout<<flowcost<<endl;            }    //getch();    return 0;}

转载于:https://www.cnblogs.com/north_dragon/archive/2010/06/03/1750812.html

相关资源:数据结构—成绩单生成器

最新回复(0)