该题是一道比较简单拆点+最大流的题目,因为每个柱子都有一定的寿命,很容易将其对应成流量,那么处理结点容量的一般方法当然是拆点法 。该题反而对边的容量没有要求,为保险起见可以设成无穷大。 该题的思路很好想,建议独立编写代码 。
推荐题目: 点击打开链接 结点法的一些见解 也可以看这里。
细节参见代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int INF = 100000000; const int maxn = 30 ; int T,cnt,a,b,m,d,kase = 0,v,c,n; struct Edge { int from, to, cap, flow; }; bool operator < (const Edge& a, const Edge& b) { return a.from < b.from || (a.from == b.from && a.to < b.to); } struct Dinic { int n, m, s, t; vector<Edge> edges; // 边数的两倍 vector<int> G[maxn*maxn*4]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号 bool vis[maxn*maxn*4]; // BFS使用 int d[maxn*maxn*4]; // 从起点到i的距离 int cur[maxn*maxn*4]; // 当前弧指针 void init(int n) { for(int i = 0; i < n; i++) G[i].clear(); edges.clear(); } void AddEdge(int from, int to, int cap) { edges.push_back((Edge){from, to, cap, 0}); edges.push_back((Edge){to, from, 0, 0}); m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BFS() { memset(vis, 0, sizeof(vis)); queue<int> Q; Q.push(s); vis[s] = 1; d[s] = 0; while(!Q.empty()) { int x = Q.front(); Q.pop(); for(int i = 0; i < G[x].size(); i++) { Edge& e = edges[G[x][i]]; if(!vis[e.to] && e.cap > e.flow) { vis[e.to] = 1; d[e.to] = d[x] + 1; Q.push(e.to); } } } return vis[t]; } int DFS(int x, int a) { if(x == t || a == 0) return a; int flow = 0, f; for(int& i = cur[x]; i < G[x].size(); i++) { Edge& e = edges[G[x][i]]; if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) { e.flow += f; edges[G[x][i]^1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } int Maxflow(int s, int t) { this->s = s; this->t = t; int flow = 0; while(BFS()) { memset(cur, 0, sizeof(cur)); flow += DFS(s, INF); } return flow; } }g; char s[maxn][maxn]; int main() { scanf("%d",&T); while(T--) { scanf("%d%d",&n,&d); for(int i=1;i<=n;i++) scanf("%s",s[i]+1); m = strlen(s[1]+1); g.init(n*m*3+5); //拆点 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { int v = s[i][j]-'0',id = (i-1)*m+j; g.AddEdge(id,id+n*m,v); } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(s[i][j] > '0') //连边 for(int x=-d;x<=d;x++) { for(int y=abs(x)-d;y<=d-abs(x);y++) { int xx = i+x , yy =j+y; if(xx == i && yy == j) continue; if(xx < 1 || xx > n || yy < 1 || yy > m) { int id = (i-1)*m + j; //与汇点相连 g.AddEdge(id+n*m,3*n*m,INF); } else { int id = (i-1)*m + j, id2 = (xx-1)*m + yy; g.AddEdge(id+n*m,id2,INF);//连边 } } } for(int i=1;i<=n;i++) scanf("%s",s[i]+1); int cnt = 0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(s[i][j] == 'L') { cnt++; //与源点相连,容量为1 int id = (i-1)*m + j; g.AddEdge(0,id,1); } int ans = g.Maxflow(0,3*n*m); if(cnt == ans) printf("Case #%d: no lizard was left behind.\n",++kase); else if(cnt-ans == 1) printf("Case #%d: %d lizard was left behind.\n",++kase,cnt - ans); else printf("Case #%d: %d lizards were left behind.\n",++kase,cnt - ans); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU 2732 Leapin' Lizards(拆点法+最大流)
原文地址:http://blog.csdn.net/weizhuwyzc000/article/details/48106491