【题解】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\n", 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\n", 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\n", 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\n", 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\n", 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\n", ISAP::edge[tsedge].f );
191         // Debug::print_flow();
192         // Debug::print_flow2();
193         printf( "%d\n", 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('\n');
205                 }
206             }
207         }
208     }
209     return 0;
210 }

 

posted @ 2017-04-19 18:49 mlystdcall 阅读(...) 评论(...) 编辑 收藏