hdu 3488 Tour (最小权匹配 / 费用流)

来源:互联网 发布:环球人物和看天下知乎 编辑:程序博客网 时间:2024/05/22 03:14

题意:有N个城市,M条街道(连接两点的距离),每条街道是单向的,现在要你设计多条路线覆盖所有的点,每条路线都是一个环,并且每个点仅能被一条路线覆盖且只经过一次(终始点除外),

分析:因为是有向圈,所以每个点的入度和出度应该都是1,故将一个点拆成两个点,入度点和出度点,然后用最佳匹配即可!(因为最佳匹配是求最大值,故我们把边权设为负值即可!)

注意:这题有重边,题目太不道德了,有重边都不说,还要猜的啊!有些题没说有重边就没重边,有些题没说有重边但是它就是有重边!无敌了都!

KM_match :

#include <iostream>#include <stdio.h>#include <string.h>using namespace std;const int inf=10000000;const int N=205;int m[N][N]; //邻接矩阵int lx[N],ly[N]; //顶点标号int fx[N],fy[N];//是否已经搜索过,S为寻找从i出发的增广轨时访问的x中的点的集合,T为访问的y中的点的集合。int match[N];int n;int dfs(int k)  //从x[k]寻找增广路{        fx[k]=1;    for(int i=1; i<=n; i++)    {        if(!fy[i]&& lx[k]+ly[i]==m[k][i])//相等子图        {            fy[i]=1;            if(match[i]==-1||dfs(match[i]))            {                match[i]=k;                return 1;            }        }    }    return 0;}int KM_match() //求解最小权匹配{    int Min;      for(int i=1; i<=n; i++)    {        lx[i]=-1;//x中顶点i的编号为与i关联的Y中边的最大权重        for(int j=1; j<=n; j++)            if(lx[i]<m[i][j])                lx[i]=m[i][j];//初始化x的顶点标号    }    memset(ly,0,sizeof(ly));//初始化y的顶点标号    memset(match,-1,sizeof(match));    for(int k=1; k<=n; k++)    {        while(1)        {            memset(fx,0,sizeof(fx));            memset(fy,0,sizeof(fy));            if(dfs(k))    break;            Min=inf;            for(int i=1; i<=n; i++)                           if(fx[i]) //x在交错树中                                    for(int j=1; j<=n; j++)                                          if(!fy[j])//y不在交错树中,扩大子图                            Min=min(Min,lx[i]+ly[j]-m[i][j]);                                               //若匹配不成功,则修改顶点标号,找到d的值             for(int i = 1 ; i <= n ;i++)  if(fx[i])  lx[i] -= Min ;         for(int i = 1 ; i <= n ;i++)  if(fy[i])  ly[i] += Min ;         }    }    int sum=0;    for(int i=1; i<=n; i++)        sum+=m[match[i]][i];      return -sum;}int main(){    int t;    cin>>t;    while(t--)    {        int M,ans;        cin>>n>>M;        for(int i=0; i<=n; i++)            for(int j=0; j<=n; j++)                m[i][j]=-inf;//即将边的权值取反        while(M--)        {            int u,v,w;            cin>>u>>v>>w;            if(m[u][v]<-w)//WA的地方,注意呀!!!                m[u][v]=-w;        }        ans=KM_match();        printf("%d\n",ans);    }    return 0;}

 

最小费用最大流 :

也是拆点,  (s,i,1,0) ,(i+n,t,1,0) ,(a,b+n,1,cost) ;

 

#include<cstdio>#include<cstring>#include<map>#include<vector>#include<cmath>#include<cstdlib>#include<stack>#include<queue>#include <iomanip>#include<iostream>#include<algorithm>using namespace std ;const int N=2500 ;const int inf=1<<30;struct node{    int u,v,c,cost,next;} edge[N*100] ;int dist[N],pre[N],head[N],vist[N];int g[N][N],top;void add(int u ,int v ,int c,int cost){    edge[top].u=u;edge[top].v=v;edge[top].c=c;edge[top].cost=cost;edge[top].next=head[u];head[u]=top++;    edge[top].u=v;edge[top].v=u;edge[top].c=0;edge[top].cost=-cost;edge[top].next=head[v];head[v]=top++;}int SPFA(int s,int t,int n){    memset(pre,-1,sizeof(pre));    memset(vist,0,sizeof(0));    for(int i =0 ; i <= n ;i++)  dist[i]=inf ;    int i,u,v;    vist[s]=1;dist[s]=0;    queue<int>q ;    q.push(s);    while(!q.empty())    {           u=q.front();           q.pop();           vist[u]=0;            for( i = head[u] ; i!=-1 ; i=edge[i].next)           {                      v=edge[i].v ;                      if(edge[i].c && dist[v] > dist[u]+edge[i].cost)                      {                                 dist[v] = dist[u]+edge[i].cost ;                                 pre[v]=i;                                 if(!vist[v])                                 {                                         vist[v]=1;                                q.push(v);                                      }                      }                      }    }      if(dist[t]==inf) return 0;    return 1;}int MFMC(int s,int t,int n){    int minflow,mincost=0,flow=0;    while(SPFA(s,t,n))    {           minflow=inf ;          for(int i=pre[t];i!=-1;i=pre[edge[i].u])                minflow=min(minflow,edge[i].c) ;          for(int i=pre[t];i!=-1;i=pre[edge[i].u])           {                     edge[i].c -= minflow;                     edge[i^1].c += minflow ;           }                        mincost += dist[t]*minflow ;           flow+=minflow ;    }    return mincost ;}int main(){    int T,n,m,s,t,u,v,c;    scanf("%d",&T);    while(T--)    {           scanf("%d%d",&n,&m);           top=0;           memset(head,-1,sizeof(head));           s=0,t=2*n+1 ;           while(m--)           {                   scanf("%d%d%d",&u,&v,&c);                   add(u,v+n,1,c);            }          for(int i = 1 ; i <= n ; i++)             add(s,i,1,0),add(i+n,t,1,0);          int ans=MFMC(s,t,t+1);          printf("%d\n",ans);       }        return 0;}



 

原创粉丝点击