• bzoj2055: 80人环游世界(可行流)


    传送门

    表示完全看不懂最小费用可行流……

    据某大佬说

    我们考虑拆点,然后进行如下连边

    $s$向$a_i$连边,权值$0$,容量$[0,m]$

    $a_i$向$a_i'$连边,权值$0$容量$[v_i,v_i]$

    如果存在边$(i,j)$,则连边$a_i'->a_i$,权值为$w_{i,j}$,容量$[0,m]$

    $a_i'$向$t$连边,权值$0$,容量$[0,m]$

    $t$向$t'$连边,权值$0$容量$[0,m]$

    然后跑个最小费用可行流

     1 //minamoto
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<queue>
     6 #define inf 0x3f3f3f3f
     7 using namespace std;
     8 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     9 char buf[1<<21],*p1=buf,*p2=buf;
    10 inline int read(){
    11     #define num ch-'0'
    12     char ch;bool flag=0;int res;
    13     while(!isdigit(ch=getc()))
    14     (ch=='-')&&(flag=true);
    15     for(res=num;isdigit(ch=getc());res=res*10+num);
    16     (flag)&&(res=-res);
    17     #undef num
    18     return res;
    19 }
    20 const int N=505,M=500005;
    21 int head[N],Next[M],ver[M],edge[M],flow[M],tot=1;
    22 inline void add(int u,int v,int e,int f){
    23     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e,flow[tot]=f;
    24     ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=-e,flow[tot]=0;
    25 }
    26 int dis[N],vis[N],cur[N],S,T,ans,s,t,kt,n,m;
    27 queue<int> q;
    28 bool spfa(){
    29     memset(dis,-1,sizeof(dis));
    30     memset(vis,0,sizeof(vis));
    31     memcpy(cur,head,sizeof(head));
    32     q.push(T),dis[T]=0,vis[T]=1;
    33     while(!q.empty()){
    34         int u=q.front();q.pop();vis[u]=0;
    35         for(int i=head[u];i;i=Next[i])
    36         if(flow[i^1]){
    37             int v=ver[i],e=edge[i];
    38             if(dis[v]<0||dis[v]>dis[u]-e){
    39                 dis[v]=dis[u]-e;
    40                 if(!vis[v]) vis[v]=1,q.push(v);
    41             }
    42         }
    43     }
    44     return ~dis[S];
    45 }
    46 int dfs(int u,int limit){
    47     if(!limit||u==T) return limit;
    48     int fl=0,f;vis[u]=1;
    49     for(int i=cur[u];i;cur[u]=i=Next[i]){
    50         int v=ver[i];
    51         if(dis[v]==dis[u]-edge[i]&&!vis[v]&&(f=dfs(v,min(limit,flow[i])))){
    52             fl+=f,limit-=f;
    53             ans+=f*edge[i];
    54             flow[i]-=f,flow[i^1]+=f;
    55             if(!limit) break;
    56         }
    57     }
    58     vis[u]=0;
    59     return fl;
    60 }
    61 void zkw(){
    62     while(spfa()) dfs(S,inf);
    63 }
    64 int main(){
    65     //freopen("testdata.in","r",stdin);
    66     n=read(),m=read(),s=2*n+1,t=s+1,kt=t+1,S=kt+1,T=S+1;
    67     for(int i=1;i<=n;++i){
    68         int x=read();
    69         add(S,i+n,0,x),add(i,T,0,x),
    70         add(s,i,0,m),add(i+n,t,0,m);
    71     }
    72     add(t,kt,0,m),add(kt,s,0,inf);
    73     for(int i=1;i<=n;++i)
    74     for(int j=i+1;j<=n;++j){
    75         int x=read();
    76         if(~x) add(n+i,j,x,inf);
    77     }
    78     zkw();
    79     printf("%d
    ",ans);
    80     return 0;
    81 }
  • 相关阅读:
    linux 查看 服务 命令
    Java Swing中键盘事件的处理(转)
    VI常用命令及快捷键(转)
    Linux source用法(转)
    无线桥接 WDS 中继(转)
    在远程桌面连接中使用任务管理器(转)
    linux 运行 级别(转)
    linux 当前用户 命令 w who(转)
    vecket适合和不适合的10种人(转)
    在查找预编译头使用时跳过解决(转)
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9580061.html
Copyright © 2020-2023  润新知