• [SCOI2007]修车


    OJ题号:

    BZOJ1070、洛谷2053

    思路:

    最初的爆零解法:
    每个工人向$S$连一条容量为$inf$、费用为$0$的边,(每个工人可以修很多车)
    每个工人向每辆车连一条容量为$1$,费用等于题目描述的边,(一个工人只能修一次同一辆车)
    每辆车向$T$连一条容量为$1$,费用为$0$的边。(每辆车总共只能修一次)
    每次增广以后将$S$到该工人之间的费用增加修理该车所用的时间,然后不停重复。
    正确解法:
    把每个工人拆成$n$个点,向每辆车连一条边,边权依次增加,表示该工人的第$i$个点表示第$i$次修理车所花的费用。
    其余边与我错误的解法相同。
    最后跑一遍最小费用最大流即可。

     1 #include<queue>
     2 #include<cstdio>
     3 #include<cctype>
     4 #include<vector>
     5 #include<cstring>
     6 inline int getint() {
     7     char ch;
     8     while(!isdigit(ch=getchar()));
     9     int x=ch^'0';
    10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    11     return x;
    12 }
    13 const int inf=0x7fffffff;
    14 int s,t;
    15 struct Edge {
    16     int from,to,remain,cost;
    17 };
    18 const int E=100000,V=800;
    19 Edge e[E];
    20 std::vector<int> g[V];
    21 int sz=0;
    22 inline void add_edge(const int u,const int v,const int w,const int c) {
    23     e[sz]=(Edge){u,v,w,c};
    24     g[u].push_back(sz);
    25     sz++;
    26 }
    27 int p[V],d[V],a[V];
    28 bool inq[V];
    29 inline void Augment() {
    30     memset(a,0,sizeof a);
    31     a[s]=inf;
    32     std::queue<int> q;
    33     q.push(s);
    34     memset(inq,0,sizeof inq);
    35     inq[s]=true;
    36     d[s]=0;
    37     for(int i=1;i<=t;i++) d[i]=inf;
    38     while(!q.empty()) {
    39         int x=q.front();
    40         q.pop();
    41         inq[x]=false;
    42         for(unsigned i=0;i<g[x].size();i++) {
    43             Edge &y=e[g[x][i]];
    44             if((d[x]+y.cost<d[y.to])&&y.remain) {
    45                 p[y.to]=g[x][i];
    46                 d[y.to]=d[x]+y.cost;
    47                 a[y.to]=std::min(a[x],y.remain);
    48                 if(!inq[y.to]) {
    49                     q.push(y.to);
    50                     inq[y.to]=true;
    51                 }
    52             }
    53         }
    54     }
    55 }
    56 int m,n;
    57 inline double EdmondsKarp() {
    58     int maxflow=0,mincost=0;
    59     while(maxflow!=n) {
    60         Augment();
    61         for(int i=t;i!=s;i=e[p[i]].from) {
    62             e[p[i]].remain-=a[t];
    63             e[p[i]^1].remain+=a[t];
    64         }
    65         mincost+=d[t];
    66         maxflow++;
    67     }
    68     return mincost;
    69 }
    70 int main() {
    71     m=getint(),n=getint();
    72     s=0,t=m*n+n+1;
    73     for(int i=1;i<=m*n;i++) {
    74         add_edge(s,i,1,0);
    75         add_edge(i,s,0,0);
    76     }
    77     for(int i=1;i<=n;i++) {
    78         for(int j=1;j<=m;j++) {
    79             int cost=getint();
    80             for(int k=1;k<=n;k++) {
    81                 add_edge((j-1)*n+k,m*n+i,1,cost*k);
    82                 add_edge(m*n+i,(j-1)*n+k,0,-cost*k);
    83             }
    84         }
    85     }
    86     for(int i=1;i<=n;i++) {
    87         add_edge(m*n+i,t,1,0);
    88         add_edge(t,m*n+i,0,0);
    89     }
    90     printf("%.2f
    ",(double)EdmondsKarp()/n);
    91     return 0;
    92 }
  • 相关阅读:
    表格的交集合集等的命令处理
    Linux中screen命令
    Linux中sed基础
    Linux中AWK基础
    聊聊开发中经历的几种后端语言
    C语言NXP S32K144 serial bootloader和C#语言bootloader PC端串口通信程序
    自己用C语言写NXP S32K144 serial bootloader
    C语言NXP S32K116 serial bootloader和C#语言bootloader PC端串口通信程序
    自己用C语言写NXP S32K116 serial bootloader
    C语言RH850 F1L serial bootloader和C#语言bootloader PC端串口通信程序
  • 原文地址:https://www.cnblogs.com/skylee03/p/7258875.html
Copyright © 2020-2023  润新知