zoukankan      html  css  js  c++  java
  • HDU1853 Cyclic Tour(最小费用最大流)

    题目大概说给一张有向图,每条边都有权值,要选若干条边使其形成若干个环且图上各个点都属于且只属于其中一个环,问选的边的最少权值和是多少。

    各点出度=入度=1的图是若干个环,考虑用最小费用最大流:

    • 每个点拆成两点u和u'
    • 源点向u连容量1费用0的边,表示这个点的出度最多为1
    • u'向汇点连容量1费用0的边,表示这个点的入度最多为1
    • 对于原图上任何一条有向边<a,b,c>,a向b'连容量1费用c的边,选择这条边后a的出度+1,b的入度+1,费用+c

    这样跑最小费用最大流,如果没满流就无解,否则MCMF就是最少权和。另外题目说2个点以上才能构成环,所以排除掉是自环的边就OK了,虽然不排除也能AC= =。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<queue>
     4 #include<algorithm>
     5 using namespace std;
     6 #define INF (1<<30)
     7 #define MAXN 222
     8 #define MAXM 222*444
     9 struct Edge{
    10     int u,v,cap,cost,next;
    11 }edge[MAXM];
    12 int head[MAXN];
    13 int NV,NE,vs,vt;
    14 
    15 void addEdge(int u,int v,int cap,int cost){
    16     edge[NE].u=u; edge[NE].v=v; edge[NE].cap=cap; edge[NE].cost=cost;
    17     edge[NE].next=head[u]; head[u]=NE++;
    18     edge[NE].u=v; edge[NE].v=u; edge[NE].cap=0; edge[NE].cost=-cost;
    19     edge[NE].next=head[v]; head[v]=NE++;
    20 }
    21 bool vis[MAXN];
    22 int d[MAXN],pre[MAXN];
    23 bool SPFA(){
    24     for(int i=0;i<NV;++i){
    25         vis[i]=0;
    26         d[i]=INF;
    27     }
    28     vis[vs]=1;
    29     d[vs]=0;
    30     queue<int> que;
    31     que.push(vs);
    32     while(!que.empty()){
    33         int u=que.front(); que.pop();
    34         for(int i=head[u]; i!=-1; i=edge[i].next){
    35             int v=edge[i].v;
    36             if(edge[i].cap && d[v]>d[u]+edge[i].cost){
    37                 d[v]=d[u]+edge[i].cost;
    38                 pre[v]=i;
    39                 if(!vis[v]){
    40                     vis[v]=1;
    41                     que.push(v);
    42                 }
    43             }
    44         }
    45         vis[u]=0;
    46     }
    47     return d[vt]!=INF;
    48 }
    49 int mxflow;
    50 int MCMF(){
    51     int res=0;
    52     mxflow=0;
    53     while(SPFA()){
    54         int flow=INF,cost=0;
    55         for(int u=vt; u!=vs; u=edge[pre[u]].u){
    56             flow=min(flow,edge[pre[u]].cap);
    57         }
    58         mxflow+=flow;
    59         for(int u=vt; u!=vs; u=edge[pre[u]].u){
    60             edge[pre[u]].cap-=flow;
    61             edge[pre[u]^1].cap+=flow;
    62             cost+=flow*edge[pre[u]].cost;
    63         }
    64         res+=cost;
    65     }
    66     return res;
    67 }
    68 
    69 int main(){
    70     int n,m,a,b,c;
    71     while(~scanf("%d%d",&n,&m)){
    72         vs=0; vt=n*2+1; NV=vt+1; NE=0;
    73         memset(head,-1,sizeof(head));
    74         for(int i=1; i<=n; ++i){
    75             addEdge(vs,i,1,0);
    76             addEdge(i+n,vt,1,0);
    77         }
    78         while(m--){
    79             scanf("%d%d%d",&a,&b,&c);
    80             if(a==b) continue;
    81             addEdge(a,b+n,1,c);
    82         }
    83         mxflow=0;
    84         int ans=MCMF();
    85         if(mxflow!=n) ans=-1;
    86         printf("%d
    ",ans);
    87     }
    88     return 0;
    89 }
  • 相关阅读:
    泛型编程 --迭代器
    cpp输入输出加速
    算法训练 加法运算(指针的一个测试)
    蓝桥杯-基础练习-字母图形
    蓝桥杯-基础练习-特殊回文数
    win10下稍微美观下Git
    mysql8.0以上版本注册驱动并建立数据库的连接公共代码
    idea使用的一些问题解决记录
    单链表逆转(递归指针实现)
    increment/decrement/dereference操作符
  • 原文地址:https://www.cnblogs.com/WABoss/p/5436448.html
Copyright © 2011-2022 走看看