[SCOI2007]蜥蜴

嘟嘟嘟

 

这题主要考网络流建图。

首先每一只蜥蜴像自己所在的石柱连边,然后如果这一只蜥蜴像能跳到的所有石柱连边,那就错了。因为每一只蜥蜴能跳到别的石柱上,然后再跳到更远的石柱上,而上述连边的意思是蜥蜴只能跳到他一步能达到的石柱上。所以,正确的连边应该是以每一个石柱,向能到达的石柱连边,容量为INF。

题中还有一点:每离开一个石柱,石柱高度减一,这相当于限制了每一个石柱能承受的蜥蜴数量。那么一个常见的做法就是拆点:将每一个石柱拆成跳到他,和从他跳走的,然后连一条容量为石柱高度的边。

最后就是对于每一个能从他跳出边界的石柱,从他跳走的点向汇点连一条INF的边。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cctype>
  8 #include<vector>
  9 #include<stack>
 10 #include<queue>
 11 using namespace std;
 12 #define enter puts("") 
 13 #define space putchar(' ')
 14 #define Mem(a, x) memset(a, x, sizeof(a))
 15 #define rg register
 16 typedef long long ll;
 17 typedef double db;
 18 const int INF = 0x3f3f3f3f;
 19 const db eps = 1e-8;
 20 const int maxn = 1205;
 21 inline ll read()
 22 {
 23     ll ans = 0;
 24     char ch = getchar(), last = ' ';
 25     while(!isdigit(ch)) {last = ch; ch = getchar();}
 26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
 27     if(last == '-') ans = -ans;
 28     return ans;
 29 }
 30 inline void write(ll x)
 31 {
 32     if(x < 0) x = -x, putchar('-');
 33     if(x >= 10) write(x / 10);
 34     putchar(x % 10 + '0');
 35 }
 36 
 37 int n, m, t, d, tot = 0;
 38 
 39 struct Edge
 40 {
 41     int from, to, cap, flow;
 42 };
 43 vector<Edge> edges;
 44 vector<int> G[maxn];
 45 void addEdge(int from, int to, int w)
 46 {
 47     edges.push_back((Edge){from, to, w, 0});
 48     edges.push_back((Edge){to, from, 0, 0});
 49     int sz = edges.size(); 
 50     G[from].push_back(sz - 2);
 51     G[to].push_back(sz - 1);
 52 }
 53 
 54 int dx[20], dy[20], st = 0;
 55 void init(int x)
 56 {
 57     for(int i = -d; i <= d; ++i)
 58         for(int j = -d; j <= d; ++j)
 59             if(i * i + j * j <= d * d) dx[++st] = i, dy[st] = j;
 60 }
 61 
 62 int getnum(int x, int y)
 63 {
 64     return m * (x - 1) + y;
 65 }
 66 
 67 bool judge(int x, int y)
 68 {
 69     if(x + d > n || x - d <= 0 || y + d > m || y - d <= 0) return 1;
 70     return 0;
 71 }
 72 
 73 void add(int x, int y)
 74 {
 75     int u = getnum(x, y) + n * m;
 76     for(int i = 1; i <= st; ++i)
 77     {
 78         int newx = x + dx[i], newy = y + dy[i];
 79         if(newx > 0 && newx <= n && newy > 0 && newy <= m) 
 80             addEdge(u, getnum(newx, newy), INF);
 81     }
 82     
 83 }
 84 
 85 int dis[maxn];
 86 bool bfs()
 87 {
 88     Mem(dis, 0); dis[0] = 1;
 89     queue<int> q; q.push(0);
 90     while(!q.empty())
 91     {
 92         int now = q.front(); q.pop();
 93         for(int i = 0; i < (int)G[now].size(); ++i)
 94         {
 95             Edge& e = edges[G[now][i]];
 96             if(!dis[e.to] && e.cap > e.flow)
 97             {
 98                 dis[e.to] = dis[now] + 1;
 99                 q.push(e.to);
100             }
101         }
102     }
103     return dis[t];
104 }
105 int cur[maxn];
106 int dfs(int now, int res)
107 {
108     if(now == t || res == 0) return res;
109     int flow = 0, f;
110     for(int& i = cur[now]; i < (int)G[now].size(); ++i)
111     {
112         Edge& e = edges[G[now][i]];
113         if(dis[e.to] == dis[now] + 1 && (f = dfs(e.to, min(res, e.cap - e.flow))) > 0)
114         {
115             e.flow += f;
116             edges[G[now][i] ^ 1].flow -= f;
117             flow += f;
118             res -= f;
119             if(res == 0) break;
120         }
121     }
122     return flow;
123 }
124 
125 int maxflow()
126 {
127     int flow = 0;
128     while(bfs())
129     {
130         Mem(cur, 0);
131         flow += dfs(0, INF);
132     }
133     return flow;
134 }
135 
136 char c[25];
137 
138 int main()
139 {
140     n = read(); m = read(); d = read();
141     init(d);
142     t = n * m * 3 + 1;
143     for(int i = 1; i <= n; ++i)
144         for(int j = 1; j <= m; ++j)
145         {
146             int x; scanf("%1d", &x);
147             if(x)
148             {
149                 int u = getnum(i, j);
150                 addEdge(u, n * m + u, x);
151                 if(judge(i, j)) addEdge(n * m + u, t, INF);
152                 add(i, j);
153             }
154         }
155     for(int i = 1; i <= n; ++i)
156     {
157         scanf("%s", c + 1);
158         for(int j = 1; j <= m; ++j)
159             if(c[j] == 'L')
160             {
161                 tot++;
162                 int u = getnum(i, j) + ((n * m) << 1);
163                 addEdge(0, u, 1); 
164                 addEdge(u, getnum(i, j), 1);
165             }
166     }
167     write(tot - maxflow()); enter;    
168     return 0;
169 }
View Code
原文地址:https://www.cnblogs.com/mrclr/p/9711219.html