zoukankan      html  css  js  c++  java
  • [SDOI2009][bzoj1877] 晨跑 [费用流]

    题面:

    传送门

    思路:

    一个点只能走一回,路径不能相交......

    显然可以转化为网络流的决策来做

    我们构建一个网络,令其最大流等于最大的跑步天数即可

    怎么构造呢?

    对于每个点只能走一次的限制,可以考虑拆点,将每个点(除了起点和终点)拆成两个,中间连一条容量为1的边,就可以了

    同时,因为要求走的距离最短,那么给每一条原图中的边赋一个费用,把最大流改成费用流即可

    这道题有一个值得深思的地方:是题目中的哪个点让你想到要用网络流而不是别的算法来做的?

    这道题我实际上是抱着“网络流那么厉害,说不定就做得了”这样的想法

    但是肯定不能看到什么题都往每一个算法上面靠,效率太低了

    不过有的题在这方面就很明显

    例如一些出入口固定的问题,显然就是dp或者网络流(深海机器人,AGC002某题)

    实际上,我们见到的题目里面,会明确告诉你算法的题目并不多,而且这种题目一般都比较难

    因此还是要培养自己看出算法来的能力啊

    Code:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define inf 1e9
     6 using namespace std;
     7 inline int read(){
     8     int re=0,flag=1;char ch=getchar();
     9     while(ch>'9'||ch<'0'){
    10         if(ch=='-') flag=-1;
    11         ch=getchar();
    12     }
    13     while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    14     return re*flag;
    15 }
    16 int n,m,cnt=-1,first[10010],dis[10010],vis[10010],ans;
    17 struct edge{
    18     int to,next,w,cap;
    19 }a[200010];
    20 inline void add(int u,int v,int cap,int w){
    21     //cout<<u<<" "<<v<<" "<<cap<<" "<<w<<"
    ";
    22     a[++cnt]=(edge){v,first[u],w,cap};first[u]=cnt;
    23     a[++cnt]=(edge){u,first[v],-w,0};first[v]=cnt;
    24 }
    25 int q[200010];
    26 bool spfa(int s,int t){
    27     int i,u,v,head=0,tail=1;memset(q,0,sizeof(q));
    28     for(i=1;i<=(n<<1);i++) dis[i]=-1;memset(vis,0,sizeof(vis));
    29     dis[t]=0;q[0]=t;vis[t]=1;
    30     while(head<tail){
    31         u=q[head++];vis[u]=0;
    32         //cout<<"spfa "<<u<<" "<<dis[u]<<"
    ";
    33         for(i=first[u];~i;i=a[i].next){
    34             v=a[i].to;
    35             //cout<<" to "<<v<<" "<<dis[v]<<" "<<a[i^1].cap<<"
    ";
    36             if(!a[i^1].cap) continue;
    37             if(~dis[v]&&dis[v]<=dis[u]+a[i^1].w) continue;
    38             dis[v]=dis[u]+a[i^1].w;
    39             if(!vis[v]){
    40                 vis[v]=1;
    41                 q[tail++]=v;
    42             }
    43         }
    44     }
    45     return ~dis[s];
    46 }
    47 int dfs(int u,int t,int limit){
    48     //cout<<"dfs "<<u<<" "<<t<<" "<<limit<<"
    ";
    49     if(u==t||!limit) return limit;
    50     int i,v,f,flow=0;vis[u]=1;
    51     for(i=first[u];~i;i=a[i].next){
    52         v=a[i].to;if(vis[v]) continue;
    53         if(dis[v]==dis[u]-a[i].w&&(f=dfs(v,t,min(limit,a[i].cap)))){
    54             flow+=f;limit-=f;
    55             a[i].cap-=f;a[i^1].cap+=f;
    56             ans+=f*a[i].w;
    57             //cout<<"ans added "<<f*a[i].w<<"
    ";
    58             if(!limit) return flow;
    59         }
    60     }
    61     return flow;
    62 }
    63 int mcmf(int s,int t){
    64     int re=0,tmp;
    65     while(spfa(s,t)){
    66         vis[t]=1;
    67         while(vis[t]){
    68             memset(vis,0,sizeof(vis));
    69             re+=dfs(s,t,inf);
    70         }
    71         //cout<<"tmp re "<<re<<"
    ";
    72     } 
    73     return re;
    74 }
    75 int main(){
    76     freopen("run.in","r",stdin);
    77     freopen("run.out","w",stdout);
    78     memset(first,-1,sizeof(first));
    79     int i,t1,t2,t3,t4,S,T;
    80     n=read();m=read();S=1;T=n<<1;
    81     for(i=2;i<n;i++) add(i,i+n,1,0);
    82     add(1,n+1,inf,0);add(n,(n<<1),inf,0);
    83     for(i=1;i<=m;i++){
    84         t1=read();t2=read();t3=read();
    85         add(t1+n,t2,1,t3);
    86     }
    87     printf("%d ",mcmf(S,T));
    88     cout<<ans<<"
    ";
    89 }

    用了某博主改进的zkw费用流,跑的好快

    博主讲的也挺好的,代码注释很全,在这里转一下链接:传送门

  • 相关阅读:
    WIN10下Java环境变量配置
    Oracle中用户的创建和权限设置
    Oracle表空间的创建与删除
    设置RHEL-7.0的运行级别
    发布项目到Tomcat(域名直接访问)
    centos7 打开80端口(网络搜集)
    MySql字符乱码问题解决(真)
    centos7安装workbench
    centos7添加Windows引导
    centos7下yum安装mysql(转)
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/8470473.html
Copyright © 2011-2022 走看看