分治法,最小权完美匹配(巨人和鬼,Ants,uva 1411)

分治法解法:

感觉能用分治法解的问题都有自相似性吧。

就是说把大的情况按某种方式切成几个小的情况,这些小的情况和大的情况是相似的。

如果满足这个条件,那么最简单的情况的解答方案是显然的。

我们只需要考虑好如何合并多个小情况即可。

跟快速排序的思想很像啊。

看紫书P227吧,讲的详细。


最小权完美匹配解法:

黑点和白点个数相同,每个黑点要找一个白点,应该要想到二分图完美匹配。

二分图匹配的算法与模板就这么几个。

唯一能当边权的东西也就是距离了。

思考一下,一个个试试,也就差不多出来了。

要求不相交,则为距离的最小权匹配。还是比较机智的。

用最小费最大流求最小权完美匹配,完美匹配一定存在。

做的时候犯了个小错误,搞了好几个小时。

当时觉得把模板里ll改成double很麻烦,ll范围也够,反正都是找最短路,开不开方不影响距离大小的比较。

事实上改double很快的,分分钟改完而且不开方是错的。原因在于反向增广时会对距离进行求和,显然平方求和会降低短边的权重,增加长边的权重,导致找出来的最短路是错的。如


黑1


黑2             白1


                    白2


若第一次找最短路时(第一次肯定不会反向增广)找了白1连黑2。

若用平方,则发现交叉的情况距离短,因此会沿着错误的路径增广。

不用则会得到正确的结果。


附上两份代码

第一份分治法

第二份用最小费最大流求最小权完美匹配

#include
#include
#define maxn 210
using namespace std;

struct Node
{
    int x,y;
    bool id;
    int bianhao;
};

Node node[maxn];
Node ji;

bool cmp1(Node& a,Node& b)
{
    if(a.y!=b.y) return a.yr) return;
    sort(node+l,node+r+1,cmp1);
    ji=node[l];
    sort(node+l+1,node+r+1,cmp2);
    int cnt1=0,cnt2=0;
    int k=r;
    while(!(ji.id!=node[k].id&&cnt1==cnt2))
    {
        if(node[k].id==ji.id) cnt1++;
        else cnt2++;
        k--;
    }
    if(ji.id) ans[node[k].bianhao]=ji.bianhao;
    else ans[ji.bianhao]=node[k].bianhao;
    dfs(l+1,k-1);
    dfs(k+1,r);
}

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d %d",&node[i].x,&node[i].y);
            node[i].id=false;
            node[i].bianhao=i;
        }
        for(int i=n+1;i<=2*n;i++)
        {
            scanf("%d %d",&node[i].x,&node[i].y);
            node[i].id=true;
            node[i].bianhao=i-n;;
        }
        dfs(1,2*n);
        for(int i=1;i<=n;i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}

#include
#include
#include
#include
#include
#include
#define maxn 210
using namespace std;

double const INF=numeric_limits::max();

struct Edge
{
    int from,to,cap,flow;
    double cost;
    Edge(int u,int v,int c,int f,double w):from(u),to(v),cap(c),flow(f),cost(w){}
};

struct MCMF
{
    int n,m;
    vectoredges;
    vectorG[maxn];
    int inq[maxn];
    double d[maxn];
    int p[maxn];
    int a[maxn];

    void init(int n)
    {
        this->n=n;
        for(int i=0;iQ;
        Q.push(s);
        while(!Q.empty())
        {
            int u=Q.front();Q.pop();
            inq[u]=0;
            for(unsigned int i=0;ie.flow&&d[e.to]>d[u]+e.cost)
                {
                    d[e.to]=d[u]+e.cost;
                    p[e.to]=G[u][i];
                    a[e.to]=min(a[u],e.cap-e.flow);
                    if(!inq[e.to]){Q.push(e.to);inq[e.to]=1;}
                }
            }
        }
        if(d[t]==INF) return false;
        flow+=a[t];
        cost+=d[t]*a[t];
        for(int u=t;u!=s;u=edges[p[u]].from)
        {
            edges[p[u]].flow+=a[t];
            edges[p[u]^1].flow-=a[t];
        }
        return true;
    }

    int MincostMaxflow(int s,int t,double& cost)
    {
        int flow=0;cost=0;
        while(BellmanFord(s,t,flow,cost));
        return flow;
    }
};

struct Node
{
    double x,y;
};

Node node1[maxn];
Node node2[maxn];

double dist(int i,int j)
{
    double xx=node1[i].x-node2[j].x;
    double yy=node1[i].y-node2[j].y;
    return sqrt(xx*xx+yy*yy);
}

int n;

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%lf %lf",&node1[i].x,&node1[i].y);
        for(int i=1;i<=n;i++)
            scanf("%lf %lf",&node2[i].x,&node2[i].y);
        MCMF mcmf;
        mcmf.init(2*n+2);
        for(int i=1;i<=n;i++)
        {
            mcmf.AddEdge(0,i,1,0);
            mcmf.AddEdge(i+n,2*n+1,1,0);
            for(int j=1;j<=n;j++)
                mcmf.AddEdge(i,j+n,1,dist(i,j));
        }
        double cost;
        mcmf.MincostMaxflow(0,2*n+1,cost);
        for(int i=1;i<=n;i++)
            for(unsigned int j=0;j=n+1&&e.to<=2*n)
                {
                    printf("%d\n",e.to-n);
                    break;
                }
            }
    }
    return 0;
}


你可能感兴趣的:(网络流,紫书-第8章-高效算法设计,分治与递归)