• 【题解】Inspection UVa 1440 LA 4597 NEERC 2009


    题目传送门:https://vjudge.net/problem/UVA-1440

    看上去很像DAG的最小路径覆盖QwQ?

    反正我是写了一个上下界网络流,建模方法清晰易懂。

    建立源$s$,向每个原图中的点连边,下界为$0$,上界为$infty$,表示在每个点可以放置无限多的人。

    建立汇$t$,每个原图中的点向汇连边,下界为$0$,上界为$infty$,表示人可以在任意一个点停止滑雪。

    对于原图中的每条弧$<u,v>$,连边$<u,v>$,下界为$1$,上界为$infty$,表示这条路至少要被检查一遍。

    然后跑一个有源汇上下界最小流就好啦OvO。

    不会求上下界网络流的看这里:http://www.cnblogs.com/mlystdcall/p/6734852.html

    输出方案?瞎搞QwQ。任选一个“需要放置人的点”开始dfs,在每个点的出边中任选一个“还需要被访问的”继续dfs,详见代码和注释。

    这样输出方案为什么是对的?时间太久远辣我已经忘辣QwQ。

    代码如下:

      1 #include <algorithm>
      2 #include <cstring>
      3 #include <cstdio>
      4 #include <queue>
      5 
      6 using namespace std;
      7 const int INF = 0x3f3f3f3f;
      8 const int MAXN = 110;
      9 
     10 namespace ISAP {
     11     const int MAXV = MAXN;
     12     const int MAXE = ( MAXV*MAXV/2 + MAXV*2 )*3;
     13     
     14     struct Edge {
     15         int u, v, c, f;
     16         Edge(){}
     17         Edge( int u, int v, int c, int f ):
     18             u(u),v(v),c(c),f(f){}
     19     }edge[MAXE<<1];
     20     int n, m, s, t, ss, tt;
     21     int head[MAXV], nxt[MAXE<<1], eid[MAXE<<1], eidx;
     22     void init( int n2, int ss2, int tt2 ) { // 初始化,设置附加源和附加汇
     23         n = n2; ss = ss2; tt = tt2;
     24         m = eidx = 0;
     25         memset( head, -1, sizeof(head) );
     26     }
     27     int adde( int u, int v, int c ) { // 添加一条只有上界的边
     28         int rtn = m;
     29         eid[eidx] = m; nxt[eidx] = head[u]; head[u] = eidx++;
     30         edge[m++] = Edge(u,v,c,0);
     31         eid[eidx] = m; nxt[eidx] = head[v]; head[v] = eidx++;
     32         edge[m++] = Edge(v,u,0,0);
     33         return rtn;
     34     }
     35     int adde2( int u, int v, int b, int c ) { // 添加一条有上下界的边,返回边的下标
     36         int rtn = adde(u,v,c-b);
     37         adde(ss,v,b);
     38         adde(u,tt,b);
     39         return rtn;
     40     }
     41     // 以下ISAP板子
     42     int prev[MAXV], dist[MAXV], num[MAXV], cur[MAXV], res[MAXV];
     43     queue<int> bfsq;
     44     void bfs() {
     45         for( int i = 1; i <= n; ++i ) dist[i] = n;
     46         dist[t] = 0; bfsq.push(t);
     47         while( !bfsq.empty() ) {
     48             int u = bfsq.front(); bfsq.pop();
     49             for( int i = head[u]; ~i; i = nxt[i] ) {
     50                 Edge &e = edge[eid[i]];
     51                 if( dist[e.v] == n ) {
     52                     dist[e.v] = dist[u] + 1;
     53                     bfsq.push(e.v);
     54                 }
     55             }
     56         }
     57     }
     58     void augment() {
     59         int u = t, flow = res[t];
     60         while( u != s ) {
     61             int i = prev[u];
     62             edge[i].f += flow;
     63             edge[i^1].f -= flow;
     64             u = edge[i].u;
     65         }
     66     }
     67     bool advance( int &u ) {
     68         for( int i = cur[u]; ~i; i = nxt[i] ) {
     69             Edge &e = edge[eid[i]];
     70             if( e.c > e.f && dist[e.v] + 1 == dist[u] ) {
     71                 prev[e.v] = cur[u] = i;
     72                 res[e.v] = min( res[u], e.c - e.f );
     73                 u = e.v;
     74                 return true;
     75             }
     76         }
     77         return false;
     78     }
     79     bool retreat( int &u ) {
     80         if( --num[dist[u]] == 0 ) return false;
     81         int newd = n;
     82         for( int i = head[u]; ~i; i = nxt[i] ) {
     83             Edge &e = edge[eid[i]];
     84             if( e.c > e.f ) newd = min( newd, dist[e.v] + 1 );
     85         }
     86         ++num[ dist[u] = newd ];
     87         cur[u] = head[u];
     88         if( u != s ) u = edge[prev[u]].u;
     89         return true;
     90     }
     91     int solve( int s2, int t2 ) { // 以s2为源,t2为汇跑最大流
     92         s = s2; t = t2;
     93         bfs();
     94         for( int i = 1; i <= n; ++i )
     95             cur[i] = head[i], ++num[dist[i]];
     96         int u = s, flow = 0;
     97         res[s] = INF;
     98         while( dist[s] < n ) {
     99             if( u == t ) {
    100                 augment();
    101                 flow += res[t];
    102                 u = s;
    103             }
    104             if( !advance(u) )
    105                 if( !retreat(u) )
    106                     break;
    107         }
    108         return flow;
    109     }
    110 }
    111 
    112 int n, s, t, ss, tt; // 点的个数,源,汇,附加源,附加汇
    113 
    114 namespace Solve {
    115     using ISAP::head;
    116     using ISAP::nxt;
    117     using ISAP::eid;
    118     using ISAP::Edge;
    119     using ISAP::edge;
    120     bool first;
    121     void dfs( int u ) { // dfs输出方案
    122         // printf( "Debug: u = %d
    ", u );
    123         if( !first ) putchar(' ');
    124         first = false;
    125         printf( "%d", u );
    126         for( int i = head[u]; ~i; i = nxt[i] ) {
    127             Edge &e = edge[eid[i]];
    128             if( e.v <= n && e.f > 0 ) { // 任选一条边走下去
    129                 // printf( "going eid = %d, from %d to %d, flow_left = %d
    ", eid[i], e.u, e.v, e.f );
    130                 --e.f;
    131                 dfs(e.v);
    132                 return;
    133             }
    134         }
    135     }
    136     void addbound() { // 把每条边流量加上下界,恢复成原图的样子,方便输出方案
    137         using ISAP::m;
    138         for( int i = 0; i < m; ++i ) {
    139             Edge &e = edge[eid[i]];
    140             if( e.u <= n && e.v <= n && e.c > 0 )
    141                 ++e.f;
    142         }
    143     }
    144 }
    145 
    146 namespace Debug { // 调试用QwQ
    147     void print_flow() {
    148         using ISAP::edge;
    149         using ISAP::Edge;
    150         using ISAP::eid;
    151         using ISAP::m;
    152         for( int i = 0; i < m; ++i ) {
    153             Edge &e = edge[eid[i]];
    154             if( e.u <= n && e.v <= n && e.c > 0 )
    155                 printf( "eid = %d, from %d to %d, flow = %d
    ", eid[i], e.u, e.v, e.f );
    156         }
    157     }
    158     void print_flow2() {
    159         using ISAP::edge;
    160         using ISAP::Edge;
    161         using ISAP::eid;
    162         using ISAP::m;
    163         for( int i = 0; i < m; ++i ) {
    164             Edge &e = edge[eid[i]];
    165             if( e.f > 0 )
    166                 printf( "eid = %d, from %d to %d, flow = %d
    ", eid[i], e.u, e.v, e.f );
    167         }
    168     }
    169 }
    170 
    171 int main() {
    172     while( scanf( "%d", &n ) == 1 ) {
    173         s = n+1, t = n+2, ss = n+3, tt = n+4;
    174         ISAP::init(tt,ss,tt);
    175         for( int i = 1; i <= n; ++i ) {
    176             int mi; scanf( "%d", &mi );
    177             while( mi-- ) {
    178                 int v; scanf( "%d", &v );
    179                 ISAP::adde2(i,v,1,INF);
    180             }
    181             ISAP::adde2(s,i,0,INF);
    182             ISAP::adde2(i,t,0,INF);
    183         }
    184         int flow1 = ISAP::solve(ss,tt);
    185         // printf( "flow1 = %d
    ", flow1 );
    186         // Debug::print_flow();
    187         // Debug::print_flow2();
    188         int tsedge = ISAP::adde2(t,s,0,INF); // 存储弧<t,s>的信息,调试用QwQ
    189         int ans = ISAP::solve(ss,tt);
    190         // printf( "t_s flow = %d
    ", ISAP::edge[tsedge].f );
    191         // Debug::print_flow();
    192         // Debug::print_flow2();
    193         printf( "%d
    ", ans );
    194         Solve::addbound(); // 把每条图中的边流量加上下界,恢复成原图的样子,方便输出方案
    195         while( ans ) {
    196             using namespace Solve;
    197             for( int i = head[s]; ~i; i = nxt[i] ) {
    198                 Edge &e = edge[eid[i]];
    199                 if( e.v <= n && e.f > 0 ) { // 任选一个点dfs,输出方案
    200                     first = true;
    201                     --e.f;
    202                     --ans;
    203                     dfs(e.v);
    204                         putchar('
    ');
    205                 }
    206             }
    207         }
    208     }
    209     return 0;
    210 }
  • 相关阅读:
    说一下 JSP 的 4 种作用域?
    CSS jquery 以动画方式显示投票结果图表
    Python动画【偶尔玩玩,挺好】
    关于Python【社区版】爬取网站图片
    Java 发送短信验证码【网建平台】
    Android发送接收短信
    如何在Java面试中介绍项目经验?
    Java面试之项目介绍
    IntelliJ IDEA 如何清理缓存和重启
    java实现支付宝接口-支付流程
  • 原文地址:https://www.cnblogs.com/mlystdcall/p/6734979.html
Copyright © 2020-2023  润新知