HDOJ 3435 - A new Graph Game 无向图分割成若干哈密顿回路(二分图最小权匹配,最小费用最大流).

                     题意:

                             给一个无向图..问能否去选择一些边组成若干个哈密顿回路..如果可以..请输出这些边之和的最小值

                     题解:

                             和有向图的差不多了...一个点拆成起点和终点...点与点之间的边注意要做两条..然后跑最小费用最大流..如果最大流不等于点数n..则是NO...否则就输出最小费用


Program:

#include<iostream>  
#include<algorithm>  
#include<stdio.h>  
#include<string.h>  
#include<math.h>  
#include<queue>  
#define MAXN 5005  
#define MAXM 500005  
#define oo 1000000007  
#define ll long long  
using namespace std;    
struct MCMF    
{    
       struct node    
       {    
              int x,y,c,v,next;     
       }line[MAXM];    
       int Lnum,_next[MAXN],pre[MAXN],dis[MAXN],flow,cost;    
       bool inqueue[MAXN];    
       void initial(int n)    
       {    
              Lnum=-1;    
              for (int i=0;i<=n;i++) _next[i]=-1;    
       }    
       void addline(int x,int y,int c,int v)    
       {    
              line[++Lnum].next=_next[x],_next[x]=Lnum;    
              line[Lnum].x=x,line[Lnum].y=y,line[Lnum].c=c,line[Lnum].v=v;    
              line[++Lnum].next=_next[y],_next[y]=Lnum;    
              line[Lnum].x=y,line[Lnum].y=x,line[Lnum].c=0,line[Lnum].v=-v;    
       }    
       bool SPFA(int s,int e)    
       {    
              int x,k,y;    
              queue<int> Q;    
              while (!Q.empty()) Q.pop();    
              memset(dis,0x7f,sizeof(dis));    
              memset(inqueue,false,sizeof(inqueue));    
              Q.push(s);    
              dis[s]=0,pre[s]=-1;    
              while (!Q.empty())    
              {    
                      x=Q.front(),Q.pop(),inqueue[x]=false;    
                      for (k=_next[x];k!=-1;k=line[k].next)      
                         if (line[k].c)    
                         {    
                               y=line[k].y;    
                               if (dis[y]>dis[x]+line[k].v)    
                               {    
                                        dis[y]=dis[x]+line[k].v;    
                                        pre[y]=k;    
                                        if (!inqueue[y])    
                                        {    
                                                inqueue[y]=true;    
                                                Q.push(y);    
                                        }    
                               }    
                         }    
              }    
              if (dis[e]>oo) return false;    
              flow=oo,cost=0;    
              for (k=pre[e];k!=-1;k=pre[line[k].x])     
                  flow=min(flow,line[k].c),cost+=line[k].v;        
              cost*=flow;    
              for (k=pre[e];k!=-1;k=pre[line[k].x])    
                  line[k].c-=flow,line[k^1].c+=flow;      
              return true;    
       }    
       void MinCostMaxFlow(int s,int e,int &Aflow,int &Acost)    
       {    
              Aflow=0,Acost=0;    
              while (SPFA(s,e))    
              {    
                     Aflow+=flow;    
                     Acost+=cost;     
              }      
       }    
}T;     
int main() 
{             
      int C,cases,i,x,y,d,n,m,s,e,Af,Ac; 
      scanf("%d",&C);
      for (cases=1;cases<=C;cases++)
      {
               scanf("%d%d",&n,&m); 
               s=n<<2,e=s+1,T.initial(e);
               for (i=1;i<=n;i++) T.addline(s,i<<1,1,0),T.addline(i<<1|1,e,1,0);
               while (m--)
               {
                       scanf("%d%d%d",&x,&y,&d);
                       T.addline(x<<1,y<<1|1,1,d),T.addline(y<<1,x<<1|1,1,d);
               }
               T.MinCostMaxFlow(s,e,Af,Ac);
               printf("Case %d: ",cases);
               if (Af==n) printf("%d\n",Ac);
                     else printf("NO\n");
      }
      return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值